ES6新特性8:Promise的使用

Pomise

含义

Promise是ES6中提供异步编程的解决方案,相比传统的通过回调函数和事件的方案更具有优越性,可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数(特别是对于具有多重回调的)。

特点

1.对象的状态不收外界影响:只有异步操作的结果才能修改内部状态。Promise共有三种状态。
Pending(进行中),Resolved(已完成又称为Fulfilled),Rejected(已失败)。
2.一旦状态改变,就不会再变更: 状态变更 Pending =>Resiloved 或者 Pending =》 Rejected。
如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。即异步操作已经完成 promise.then 再去定义也能正常返回结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
如:
只能打印出“成功”,因为执行 resolve(); 方法后 状态已经变更,再执行 reject()也不会再变更状态。

new Promise(
    /* 执行器 executor */
    function (resolve, reject) {          // 一段耗时很长的异步操作

      resolve();     // 数据处理完成
      reject();       // 数据处理出错
    }
 ).then(function A() { 
     console.log('成功');      // 成功,下一步
  }, function B() {  
     console.log('失败');       // 不能打印出
});

缺陷

1:一旦新建,就会立即执行,无法取消。
2:如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。不能使用 try catch 来捕捉异常。
3:当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
4:同async 用法相比,大量then的使用,代码较为繁琐。

基本用法

Promise是一个对象,生成Promise实例,构造函数接收一个函数作为参数。Promise实例使用then来处理回调。then可以接收两个参数,第一个是成功后的回调,第二个是失败时的回调(非必填)。

1:创建后会立即执行。看如下代码的执行顺序。

var promise = new Promise(function(resolve, reject) {
    console.log('执行promise');   //首先执行
    resolve();
  });
  
  promise.then(function() {
    console.log('promise执行成功');  //最后执行
  });
  
  console.log('创建完Promise后'); //执行顺序第二位

/* 打印顺序
 执行promise
创建完Promise后
promise执行成功
*/

2:Promise 的链式调用。
使用 then 和 catch 方法实现链式调用。虽然then 的入参有两个,但是失败状态不建议在then内部实现,因为如果是链式调用的话,会造成代码繁琐,采用 catch方法,可简化实现方式。
采用统一抛出异常方式 ,在链式调用后catch方法内捕捉。避免每个then,都去实现 reject的回调。

function getJson(url){
    return new Promise(function(resolve, reject) {
        if(url=='error.html')
        {
            throw new Error('抛出异常');
            
        }
        
        resolve(url+'执行完毕');
      });

}
//这种写法也能实现功能,但是要有多层回调,那样代码的可读性就太差了
getJson('test1.html', '').then(function(data1) {
    console.log('第一次调用, 返回的数据是:', data1);
    return getJson('test2.html', data1).then(function(data1) {
        console.log('第一次调用, 返回的数据是:', data1);
       return getJson('test2.html', data1);
});
})
//采用下面方法实现链式调用和异常处理。
getJson('test1.html', '').then(function(data1) {
    console.log('第一次调用, 返回的数据是:', data1);
    return getJson('test2.html', data1);
}).then(function(data2) {
    console.log('第二次调用, 返回的数据是:', data2);
    return getJson('error.html', data2);
}).then(function(data3) {
    console.log('第三次调用, 返回的数据是:', data3);
}).catch(function(error) {
    //用catch捕捉前面的错误
    console.log('sorry, 请求失败了, 这是失败信息:', error);
});

返回结果

注意:
1:如果Promise状态已经变成Resolved,再抛出错误是无效的。
2:catch方法返回的还是一个 Promise 对象,因此后面还可以接着调用then方法。
应用场景可以用来程序出现异常,传异常信息至服务器。

image.png

其他方法

1:Promise.all
将多个Primise 实例合并成一个实例,只有当所有实例都变成resolved状态,或者其中一个变成rejected状态,才会执行回调。

function getJson(url,data){
    return new Promise(function(resolve, reject) {
        if(url=='error.html')
        {
            throw new Error('抛出异常');
            
        }
        
        resolve(url+'执行完毕:'+data,id);
      });

}
function getPromises(array){
   return  array.map(function (id) {
        if(id==4)
        {
            throw new Error('抛出异常');
        }
        return getJson("/post/" + id + ".json",id);
      });
}
//执行中抛出异常
  Promise.all(getPromises([1,2,3,4,5])).then(function (posts) {
      console.log('全部执行完毕');

  }).catch(function(reason){
      console.log('抛出了异常');

  });
//全部执行完毕
  Promise.all(getPromises([1,2,3,5])).then(function (posts) {
      console.log('全部执行完毕');

  }).catch(function(reason){
      console.log('抛出了异常');

  });

Promise.race()
样是将多个Promise实例,包装成一个新的Promise实例,多个实例有一个实例状态改变,实例状态就改变了,返回的第一个改变的实例状态。

 Promise.race(getPromises([1,2,3,4,5])).then(function (posts) {
      console.log('执行完毕');

  }).catch(function(reason){
      console.log('抛出了异常');

  });
//第一个执行完毕后就不会再调用回调函数。

两个实用的扩展方法

done()
Promise对象的回调链,不管以then方法或catch方法结尾,要是最后一个方法抛出错误,都有可能无法捕捉到(因为Promise内部的错误不会冒泡到全局)。因此,我们可以提供一个done方法,总是处于回调链的尾端,保证抛出任何可能出现的错误。

代码实现
Promise.prototype.done = function (onFulfilled, onRejected) {
  this.then(onFulfilled, onRejected)
    .catch(function (reason) {
      // 抛出一个全局错误
      setTimeout(() => { throw reason }, 0);
    });
};

finally()
finally方法用于指定不管Promise对象最后状态如何,都会执行的操作。它与done方法的最大区别,它接受一个普通的回调函数作为参数,该函数不管怎样都必须执行。实例可以用来网络请求中的loading

Promise.prototype.finally = function (callback) {
  let P = this.constructor;
  return this.then(
    value  => P.resolve(callback()).then(() => value),
    reason => P.resolve(callback()).then(() => { throw reason })
  );
};

你可能感兴趣的:(ES6新特性8:Promise的使用)