异步发展流程 —— Promise 的基本使用

2018-10-11 admin

在这里插入图片描述

Promise 简介

Promise 是 ES6 的新特性,提供了对 js 异步编程控制的新的解决方案,在过去书写异步代码时要靠回调函数,当异步操作依赖于其他异步操作的返回值时,会出现一种现象,被程序员们称为 “回调地狱”,即多层回调函数嵌套,这种代码的可读性、维护性都很差,因此诞生了 Promise,当然 Promise 并不是完全摆脱回调,而只是改变了传递回调的位置,大大减少了回调函数嵌套。

<br/>

Promise 的使用

1、实例方法 then

Promise 中的代码默认是同步执行的,then 方法中的回调在微任务队列中执行,在 Promise 的 then 方法中支持传入两个参数,一个是成功的回调,一个是失败的回调,在 Promise 中调用了 resolve 方法,就会在 then 中执行成功的回调,调用了 reject 方法,就会在 then 中执行失败的回调,成功的回调和失败的回调只能执行一个,resolvereject 方法调用时传入的参数会传递给 then 方法中对应的回调函数。

// 执行 resolve
let p = new Promise((resolve, reject) => {
    console.log(1);
    resovle(3);
});

console.log(2);

p.then(data => {
    console.log(data);
}, err => {
    console.log(err);
});

// 1
// 2
// 3
// 执行 reject
let p = new Promise((resolve, reject) => {
    reject();
});

p.then(() => {
    console.log(1);
}, () => {
    console.log(2);
});

// 2

如果 Promise 中发生错误,就会在 then 中执行失败的回调。

// 失败的回调
let p = new Primise((resolve, reject) => {
    throw new Error();
});

p.then(() => {
    console.log(1);
}, () => {
    console.log("报错啦");
});

// 报错啦

当同一个 Promise 实例的 then 方法多次调用时,就会多次执行。

// 多次调用 then
let p = new Promise((resolve, reject) => {
    resolve("成功");
});

p.then(data => {
    console.log(data);
});

p.then(data => {
    console.log(data);
});

// 成功
// 成功

2、Promise 的链式调用

Promise 支持链式调用,每次调用一次 then 方法都会返回一个新的 Promise实例,如果该 then 方法中执行的回调函数有返回值,并且这个返回值会作为返回的下一个 Promise 实例的 then 方法回调的参数,如果 then 方法的返回值是一个 Promise 实例,那就返回一个新的 Promise 实例,将 then 返回的 Promise 实例执行后的结果作为返回 Promise 实例回调的参数。

// 链式调用 then
function read(url) {
    return new Promise((resolve, reject) => {
        fs.readFile(url, "utf8", (err, data) => {
            if (err) reject(err);
            resolve(data);
        })
    });
}

read("1.txt").then(data => {
    // 假设此时读到的内容为 Hello world
    return data;
}, err => {
    console.log(err);
}).then(data => {
    console.log(data);
    // Hello world
}, err => {
    console.log(err);
});

read("1.txt").then(data => {
    // 假如此时读到的 1.txt 的内容为 2.txt 的字符串,2.txt 的内容为 Hello world
    return read(data);
}, err => {
    console.log(err);
}).then(data => {
    console.log(data);
    // Hello world
}, err => {
    console.log(err);
});

在 Promise 实例的 then 中如果有错误产生,在返回的新的 Promise 实例中的 then 方法中会执行错误的回调。

// 链式调用 then 出错
let p = new Promise((resolve, reject) => {
    resolve();
});

p.then(() => {
    console.log("success", 1);
    throw new Error();
}, () => {
    console.log("error", 1);
}).then(() => {
    console.log("success", 2);
}, () => {
    console.log("error", 2)
})

// success 1
// error 2

在 Promise 中有三个状态:

  • pending:等待态
  • fulfilled:成功态
  • rejected:失败态

Promise 实例的状态只能从 pendingfulfilled 或从 pendingrejected,状态一旦发生变化就不可逆,所以 Promise 实现链式调用与 jQuery 不同,返回的不是 this,只能是一个新的 Promise。

3、实例方法 catch

在 Promise 中实例的 catch 方法可以捕获链式调用中的异常,不需要每次调用 then 方法中都传入错误的回调,在链式调用的过程中只要有任何一个 then 中出现错误,都会被 catch 方法捕获到。

// catch 方法
let p = new Promise((resolve, reject) => {
    resolve();
});

p.then(() => {
    throw new Error();
    console.log("success", 1);
}).then(() => {
    console.log("success", 2);
}).catch(() => {
    console.log('出错了');
});

// 出错了

p.then(() => {
    console.log("success", 1);
}).then(() => {
    throw new Error();
    console.log("success", 2);
}).catch(() => {
    console.log('出错了');
});

// success 1
// 出错了

4、静态方法 Promise.all

Promise 中的静态方法 all 可以实现多个 Promise 实例的并行,当所有结果都为成功时,返回一个数组,该数组存储的为每一个 Promise 实例的返回结果,每一个 Promise 实例的返回顺序先后不固定,但是返回值的数组内存储每一个 Promise 的返回值的结果按照最初传入的顺序排列,all 方法的返回值为一个新的 Promise 实例,返回的数组作为返回新 Promise 的 then 方法成功回调的参数。

all 传入的参数数组中的 Promise 实例执行时,只要有一个失败,则直接返回该 Promise 实例失败的结果或错误信息。

// Promise.all 方法
let p1 = new Promise((resolve, reject) => {
    resolve(1);
});

let p2 = new Promise((resolve, reject) => {
    resolve(2);
});

Promise.all([p1, p2]).then(data => {
    console.log(data);
});

// [1, 2]
// Promise.all 错误捕获
let p1 = new Promise((resolve, reject) => {
    resolve(1);
});

let p2 = new Promise((resolve, reject) => {
    reject(2);
});

Promise.all([p1, p2]).then(data => {
    console.log(data);
}).catch(err => {
    console.log(err);
});

// 2

5、静态方法 Promise.race

Promise 的静态方法 race 的用法和 all 类似,参数同为一个存储 Promise 实例的数组,返回值同样是一个新的 Promise 的实例,不同的是,数组中的 Promise 实例只有一个结果为成功,那就直接返回这个结果(只取出最快返回的结果),在没有成功的结果之前有一个出错,就直接返回这个错误。

// Promise.race 方法
let p1 = new Promise((resolve, reject) => {
    setTimeout(() => resolve(1), 2000);
});

let p2 = new Promise((resolve, reject) => {
    setTimeout(() => resolve(2), 1000);

});

Promise.race([p1, p2]).then(data => {
    console.log(data);
}).catch(err => {
    console.log(err);
});

// 2
// Promise.race 错误捕获
let p1 = new Promise((resolve, reject) => {
    setTimeout(() => reject(1), 1000);
});

let p2 = new Promise((resolve, reject) => {
    setTimeout(() => resolve(2), 2000);

});

Promise.race([p1, p2]).then(data => {
    console.log(data);
}).catch(err => {
    console.log(err);
});

// 1

6、静态方法 Promise.resolve

Promise 的静态方法 resolve 可以直接将 Promise 的状态变为成功并返回一个新的 Promise 实例,resolve 的参数会传递给返回的新 Promise 实例 then 中成功回调。

// Promise.resolve 方法
Promise.resolve('hello').then(data => {
    console.log(data);
});

// hello

7、静态方法 Promise.reject

Promise 的静态方法 rejectresolve 使用完全相同,都返回一个新的 Promise 实例,不同的是 reject 的参数会传递给新 Promise 实例的 then 方法失败回调。

// Promise.reject 方法
Promise.reject('出错了').then(null, err => {
    console.log(err);
});

// 出错了

当成功的回调不传递时,可以使用 null 代替,因为 null 作为参数会被忽略掉,将参数穿透到下一个 then 的回调中。

原文链接:https://segmentfault.com/a/1190000016653923

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-42446.html

文章标题:异步发展流程 —— Promise 的基本使用

相关文章
Angular2-primeNG文件上传模块FileUpload使用详解
近期在学习使用Angular2做小项目,期间用到很多primeNG的模块。 本系列将结合实战总结angular2-primeNG各个模块的使用经验。 文件上传模块FileUploadModule 首先要在使用该组件的模块内导入文件上传模块 ...
2017-03-09
YouTube正式默认使用HTML5视频播放器
YouTube视频网站现在默认使用HTML5播放器,这意味着更好的性能、 稳定性、 电池寿命和甚至是更好的安全性。现在用户通过Chrome、IE 11、Safari 8和Beta版本的Firefox进行浏览的时候都默认使用HTML5视频播放...
2015-11-12
从2014年的发展来展望JS的未来将会如何
&lt;font face=&quot;寰�杞�闆呴粦, Arial, sans-serif &quot;&gt;2014骞达紝杞�浠惰�屼笟鍙戝睍杩呴€燂紝鍚勭�嶈��瑷€灞傚嚭涓嶇┓锛屼互婊¤冻鐢ㄦ埛涓嶆柇鍙樺寲鐨勯渶姹傘€傝繖浜涜��...
2015-11-12
12个你未必知道的CSS小知识
虽然CSS并不是一种很复杂的技术,但就算你是一个使用CSS多年的高手,仍然会有很多CSS用法/属性/属性值你从来没使用过,甚至从来没听说过。 1.CSS的color属性并非只能用于文本显示 对于CSS的color属性,相信所有Web开发人员...
2015-11-12
ajax为什么令人惊异?ajax的优缺点
使用Ajax的最大优点,就是能在不更新整个页面的前提下维护数据。这使得Web应用程序更为迅捷地回应用户动作,并避免了在网络上发送那些没有改变的信息。 Ajax不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。就像DHT...
2015-11-12
HTML5的5个不错的开发工具推荐
HTML5规范终于在今年正式定稿,对于从事多年HTML5开发的人员来说绝对是一个重大新闻。数字天堂董事长,DCloud CEO王安也发表了文章,从开发者和用户两个角度分析了HTML对两个人群的优势。其实,关于HTML5的开发工具,我们以往的...
2015-11-12
JavaScript教程:JS中的原型
Keith Peters 几年前发表的一篇博文,关于学习没有“new”的世界,其中解释了使用原型继承代替构造函数。两者都是纯粹的原型编码。 标准方法(The Standard Way) 一直以来,我们学习的在 JavaScript 里创建对...
2015-11-12
AJAX的浏览器支持
AJAX 的要点是 XMLHttpRequest 对象。 不同的浏览器创建 XMLHttpRequest 对象的方法是有差异的。 IE 浏览器使用 ActiveXObject,而其他的浏览器使用名为 XMLHttpRequest 的 Jav...
2015-11-12
Riot.js:不足1KB的MVP客户端框架
Riot.js是一款MVP(模型-视图-呈现)开源客户端框架,其最大的特点就是体积非常小,不足1KB,虽然体积小,但它可以帮助用户构建大规模的Web应用程序。 Riot.js是由Moot公司开发,目前最新版本为v0.9.2,遵循MIT开源许...
2016-03-11
JavaScript的组成
一个完整的JavaScript由3个部分组成:核心(ECMAScript) 文档对象模型(DOM) 浏览器对象模型(BOM) ECMAScript 描述了该语言的语法和基本对象 ; DOM 描述了处理网页内容的方法和接口 ; BOM 描...
2015-11-12
回到顶部