原文链接 http://www.bestvist.com/p/54
Promise 简介
ECMAscript6 原生提供了 Promise 对象, 由浏览器直接支持, 目前大多数浏览器都已经实现了, 低版本浏览器可以使用 es6-promise 库来填平兼容性问题. Promise 最大的好处是把执行代码和处理代码分离开, 使异步操作逻辑更加清晰.
Promise 特点
1, 对象的状态不受外界影响
Promise 对象代表一个异步操作, 有三种状态:
pending - 初始状态.
fulfilled - 操作成功完成.
rejected - 操作失败.
只有异步操作的结果可以决定当前是哪一种状态, 其他操作都不会影响状态改变, 这也是 Promise 最本质的特性, 对于调用者的一种承诺
2, 一旦状态改变, 就不会再变
Promise 对象的状态改变, 只有两种情况: 从 Pending 变为 Resolved 和从 Pending 变为 Rejected. 只要这两种情况发生, 状态就会固定, 不会再变了, 会一直保持这个结果, 与事件不同的是, 就算改变已经发生了, 再对 Promise 对象添加回调函数, 也会立即得到这个结果, 而事件一旦错过再去监听, 就不会得到结果.
Promise 优缺点
优点:
有了 Promise 对象, 就可以将异步操作以同步操作的流程表达出来, 避免了层层嵌套的回调函数 Promise
对象提供统一的接口, 使得控制异步操作更加容易
缺点:
无法取消 Promise, 一旦新建它就会立即执行, 无法中途取消
如果不设置回调函数, Promise 内部抛出的错误, 不会反应到外部
当处于 Pending 状态时, 无法得知目前进展到哪一个阶段 (刚刚开始或者即将完成)
Promise.prototype.then
Promise.prototype.then 方法返回的是一个新的 Promise 对象, 因此可以采用链式写法
- ajax("http://www.bestvist.com").then((json) => {
- return json.post;
- }).then((post) => {
- // post 处理
- });
代码中使用 then 方法, 指定了两个回调函数. 第一个回调函数完成后, 会将返回结果作为参数, 传入第二个 then 中的回调函数执行.
- ajax("http://www.bestvist.com").then((jsonURL) => {
- return ajax(jsonURL);
- }).then((post) => {
- // post 处理
- });
如果第一个回调函数返回的是 Promise 对象, 后一个回调函数会等待该 Promise 对象的运行结果, 等 Promise 运行结果返回, 再进一步调用.
这种设计使得嵌套的异步操作, 可以被很容易得改写, 把回调函数的 "横向发展" 改为了 "向下发展".
Promise.prototype.catch
Promise.prototype.catch 错误捕捉方法是 Promise.prototype.then(null, rejection) 的别名, 用来指定发生错误时的处理函数.
- ajax("http://www.bestvist.com").then((post) => {
- throw Error();
- }).catch((error) => {
- // 捕捉回调函数运行时发生的错误进行处理
- console.log('error:' + error);
- });
Promise 对象的错误具有 "冒泡" 性质, 会一直向后传递, 直到被捕获为止.
- ajax("http://www.bestvist.com").then((jsonURL) => {
- return ajax(jsonURL);
- }).then((comments) => {
- throw Error();
- }).catch((error) => {
- // 处理前两个回调函数的错误
- console.log('error:' + error);
- });
- Promise.resolve
Promise.resolve 方法可以将现有对象转为 Promise 对象. 如果 Promise.resolve 方法的参数, 不是 thenable 对象 (具有 then 方法的对象 ), 则返回一个新的 Promise 对象, 且它的状态为 fulfilled.
- const resolve = Promise.resolve('promise resolve');
- resolve.then((s)=>{
- console.log(s)
- });
输出结果:
promise resolve
如果 Promise 对象的实例状态为 fulfilled, 回调函数会立即执行, Promise.resolve 方法的参数就是回调函数的参数.
如果 Promise.resolve 方法的参数是一个 Promise 对象的实例, 则会返回该 Promise 实例.
Promise.reject
Promise.reject(reason) 方法与 resolve 方法类似, 也会返回一个新的 Promise 实例, 但该实例的状态为 rejected.Promise.reject 方法的参数, 会被传递给实例的回调函数.
- const reject = Promise.reject('promise reject');
- reject.then(null, (err) => {
- console.log(err)
- });
输出结果:
- promise reject
- Promise.all
Promise.all 方法用于将多个 Promise 实例, 包装成一个新的 Promise 实例, 该方法一般接受一个数组作为参数, 但不一定是数组, 只要具有 iterator 接口. 且返回的每个成员都是 Promise 实例.
- const getRandom = () => +(Math.random()*1000).toFixed(0);
- const ajax = (taskID) => new Promise(resolve => {
- let timeout = getRandom();
- console.log(`taskID=${taskID} start.`);
- setTimeout(function() {
- console.log(`taskID=${taskID} finished in time=${timeout}.`);
- resolve(taskID)
- }, timeout);
- });
- Promise.all([ajax(1),ajax(2),ajax(3)])
- .then(resultList => {
- console.log('results:',resultList);
- });
输出结果:
- taskID=1 start.
- taskID=2 start.
- taskID=3 start.
taskID=2 finished in time=27.
taskID=3 finished in time=257.
taskID=1 finished in time=876.
results: [1, 2, 3]
Promise.all 状态分为两种:
只有 ajax(1),ajax(2),ajax(3) 的状态都变成 fulfilled, 返回的状态才会变成 fulfilled, 此时 ajax(1),ajax(2),ajax(3) 的返回值组成一个数组, 传递给 Promise.all 的回调函数.
只要 ajax(1),ajax(2),ajax(3) 之中有一个是 rejected, 返回的状态就变成 rejected, 此时第一个被 reject 的实例的返回值, 会传递给 Promise.all 的回调函数.
Promise.race
Promise.race 方法也是将多个 Promise 实例, 包装成一个新的 Promise 实例, 与 Promise.all 不同的是一旦有状态改变, 就会返回第一个状态改变的 Promise 实例返回值.
- const getRandom = () => +(Math.random()*1000).toFixed(0);
- const ajax = (taskID) => new Promise(resolve => {
- let timeout = getRandom();
- console.log(`taskID=${taskID} start.`);
- setTimeout(function() {
- console.log(`taskID=${taskID} finished in time=${timeout}.`);
- resolve(taskID)
- }, timeout);
- });
- Promise.race([ajax(1),ajax(2),ajax(3)])
- .then(result => {
- console.log('results:',result);
- });
输出结果:
- taskID=1 start.
- taskID=2 start.
- taskID=3 start.
taskID=2 finished in time=59.
results: 2
taskID=3 finished in time=707.
taskID=1 finished in time=854.
Promise.race 虽然返回第一个状态改变的 Promise 实例, 但不能阻止其他 Promise 实例状态改变.
如果 Promise.all 方法和 Promise.race 方法的参数, 不是 Promise 实例, 就会调用 Promise.resolve 方法, 将参数转为 Promise 实例, 再进一步处理.
来源: http://www.qdfuns.com/article/23172/00dd6927c000ea927e3a580bdaa39700.html