浅谈ES6的promise

promise对象的两个特点:
  1. 对象的状态不受外界影响。promise对象有三种状态:Pending(进行中),Resolved(已完成,也叫fulfilled)和rejected(已失败)。
  2. 一旦状态改变,就不会再变。
构造promise函数:
var promise = new Promise(function(resolve, reject){
     if (/* 异步操作成功*/) {
          resolve(value);
     } else {
          reject(error);
     }
});
其中resolve函数的作用:将promise的状态从“未完成”变成“成功”,pending -> resolved
reject函数作用:将promise状态从pending -> rejected
 
.then的使用
1) 构造promise函数后,可以使用.then来指定对应的resolve和reject函数。
  promise.then(function(value){
       // success
  }, function(error){
       // failure
  })
 
2)resolve的执行顺序问题
  new Promise((resolve, reject) => {
       resolve(1);
       console.log(2);
  }).then(r => {
    console.log(r);
  });
以上代码运行结果为:先打印2,再打印1。这是因为resolve是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。
  new Promise((resolve, reject) => {
         reject('error');
         console.log(2);
  }).catch(r => {
         console.log(r);
  });
同理,对于reject也是一样,运行结果为先打印2,再打印error
 
这里面牵涉到一个事件循环的原理。为了更好的理解,插播一下事件循环的原理:
众所周知,JS是单线程。为了解决JS单线程漫长等待的问题,产生了两种JS的执行方式,即同步执行和异步执行。同步执行是指,一个任务结束了然后再执行下一个任务,异步执行是指CPU跳过等待时间长的任务,先去执行后面的任务。
异步执行的机制实现如下:
1 所有任务都在主线程上执行,形成一个执行栈。
2 主线程之外,有一个任务队列。系统会把异步任务防在任务队列里,然后继续去执行后续的任务。
3 执行栈中的任务执行完毕,系统就会去任务队列里读取异步任务,如果此时异步任务已经结束了等待状态,就会从任务队列进入执行栈。
4 主线程不断重复以上过程,就是事件循环的过程。
5 定时器setTimeout和setInterval也会将事件插入到任务队列中,也就是必须要等到当前代码执行执行完,主线程才会去执行指定的回调函数。所以没有办法保证,回调函数一定会在指定的时间内执行。
6 DOM的变动,通常不会立即执行,而是16毫秒执行一次,使用requestAnimationFrame()的效果要好于setTimeout()。
 
3)链式的then
采用链式的then,可以指定一组按照次序调用的回调函数。第一个回调函数完成以后,会将返回结果作为参数,传入下一个回调函数中。
 
.catch的使用
Promise.prototype.catch方法是.then(null, reject)的别名,用于指定发生错误时的回调函数。主要有两个用户:在异步操作抛出错误状态变成rejected的时候调用.catch指定的回调函数,在then方法指定的回调函数执行发生错误时会被.catch方法捕获。
 
使用.catch捕获错误如下:
var promise = new Promise(function(resolve, reject) {
  throw new Error('test');
});
promise.catch(function(error) {
  console.log(error);
});
运行结果为:
Error: test error
    at <anonymous>:2:9
    at Promise (<anonymous>)
    at <anonymous>:1:15
等同于:
var promise = new Promise(function(resolve, reject) {
  reject(new Error('test'));
});
promise.catch(function(error) {
  console.log(error);
});
 
promise.all()
用于将多个promise实例,包装成一个新的promise实例。
var p = Promise.all([p1, p2, p3]);
P的状态由p1,p2,p3决定:
1 p1,p2,p3的状态都变成fulfilled,p的状态才会变成fulfilled。
2 只要有一个返回的状态是rejected,那么p的状态就变成rejected,且第一个被rejected的实例的返回值,会传递给p的回调函数。注意,如果实例定义了自己的catch方法,则不会触发promise.all()的catch方法。
var p1 = new Promise(function (resolve) {
  setTimeout(function () {
  resolve("Hello");
  }, 3000);
});
var p2 = new Promise(function (resolve) {
  setTimeout(function () {
  resolve("World");
  }, 1000);
});
Promise.all([p1, p2]).then(function (result) {
  console.log(result);
});
上述运行结果为: ["Hello", "World"],因为Promise.all方法会按照数组里面的顺序返回结果。
 
promise.race()
var p = Promise.race([p1, p2, p3]);
也是将多个promise实例包装成一个新的promise实例。与上面的方法不同的是,只要p1p2p3有一个实例率先改变了状态,p的状态也跟着改变,而且率先改变的promise的返回值,会传给P的回调函数。
原文地址:https://www.cnblogs.com/xmll/p/7275789.html