Promise是异步编程的解决方案之一,它比传统的解决方案(回调函数和事件)更加合理和强大。
Promise:
1、可以说是一个容器,里面保存着某个未来才会结束的事件。
2、Promise是个对象,从它可以获取异步操作的消息。

Promise两个特点:
(1)对象状态不受外界影响。三种状态:Pending(进行中),fulfilled(已成功),rejected(已拒绝).只有异步操作的结果可以决定当前是哪一种转态,任何其他操作都无法改变这个状态。
(2)一旦状态改变就不会在变。只有两种改变方法:pending-->fulfilled,pending-->rejected.

注意:有了Promise对象,可以将异步操作以同步操作的流程表达出来。

利用Promise对象实现Ajax操作

var getJSON =  function(url){
    var promise = new Promise(function(resolve,reject){
        var client = new XMLHttpRequest();
        client.open('GET',url);
        client.onreadystatechange = handler;
        client.responseType = 'json';
        client.setRequestHeader("Accept","application/json");
        client.send();
        function handler(){
            if(this.readyState !==4){
                return;
            }
            if(this.status === 200){
                resolve(this.response);
            }else{
                reject(new Error(this.statusText);
           }
       };
      });
      return promise;
     };
     getJSON("/posts.json").then(function(json){
         console.log('Contents:'+json);
         },function(error){
         console.log('出错了',error);
     });
                

注意:resolve和reject的Promise是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。
clipboard.png
由上面的例子可以看出,后续操作最好放到then方法中,不要直接写在resolve或reject后面,最好在他们前面加上renturn瑜伽。因为调用resolve和reject后,Promise的使命就完成了。

clipboard.png

Promise实例具有的方法

【1】Promise.prototype.then()
作用:为Promise实例添加状态改变时的回调函数。
这个方法可以包含两个参数;
参数1:resolved状态的回调函数。
参数2:rejected转态的回调函数。
then方法返回的是一个Promise实例,所以可以采用链式方法,链式方法可以指定一组按照次序调用的回调函数。前一个回调函数有可能返回的还是一个Promise对象(有异步操作),后一个回调函数会等待该Promise对象的状态发生变化,再被调用。

【2】Promise.prototype.catch()
可以说是then方法的别名,用来指定发生错误时的回调函数。
then方法的第二个参数是用来定义rejected的回调函数,但最好不这么写,始终用catch方法去捕捉错误比较好。
好的写法和不好的写法
clipboard.png
clipboard.png

then()和catch()方法
异步操作抛出错误,状态会被置为Rejected,之后调用catch方法指定的回调函数可以处理这个错误。then()方法中的指定回调函数在运行中抛出错误,也会被catch方法捕获。

then方法等价于catch方法的写法:
clipboard.png

证明Promise状态一旦改变,不会再变化。
Promise在resolve语句后面再抛出错误,并不会被捕获,等于没有抛出。因为Promise的状态一旦改变,就会保持该状态,不会再改变了。
clipboard.png

如果不指定catch方法,错误是不会捕获,也不会传递到外层代码。这个和传统的try,catch是不同的。

Node有个unhandleRejection事件,专门监听未捕获的reject错误。
【3】Promise.all()
Promise.all()方法中的参数不一定是数组,但必须具有Interator接口,并且返回的每个成员都是Promise实例。(但 常用的是数组)
var p = Promise.all([p1,p2,p3]);
p的状态由p1,p2,p3决定:
1、p1,p2,p3全变为fulfilled,p的状态会变为fulfilled。
2、p1,p2,p3中有一个变为rejected,p的状态就会变为rejected。

另一点:
如果参数的Promise实例自身定义了catch方法,那么它被rejected时并不会触发Promise.all()的catch方法。
例子:
(1)p2自己本身有catch,所以Promise.all()的catch捕获不到。
clipboard.png
(2)p2自己本身不加catch,这样Promise.all()的catch才能捕获到。
clipboard.png

【4】Promise.race()
和Promise.all()的不同之处是:参数有一个实例率先发生变化,相应的状态就会发生变化。

【5】Promise.resolve()
作用:将现有的对象转为Promise对象。
clipboard.png

该方法的参数有四种情况:
1、参数是Promise实例。
此时Promise.resolve不用做任何修改,原封不动的返回这个实例即可。
2、参数是thenable对象
问:什么是thenable对象?
具有then方法的对象。
如:
let thenable = {

then:function(resolve,reject){
    resolve(42);
}};

Promise.resolve方法会将对象转为Promise对象,然后可以立即执行thenable对象的then方法。
clipboard.png

3、不具有then方法的对象或者根本不是对象
Promise.resolve()方法返回了一个新的Promise对象,状态为resolved。
并且该方法的参数会同时传给回调函数。

4、不带有任何参数
Promise.resolve方法允许在调用时不带有参数,而直接返回一个Resolved状态的Promise对象。所以想要得到一个Promise对象,最简单的方法就是直接调用Promise.resolve()。

【5】Promise.reject()
作用:返回一个新的Promise实例,状态为Rejected。
clipboard.png

等价于
clipboard.png

两个不在es6中,却很有用的方法

【1】done() 放在回调链的末尾,保证抛出任何可能出现的错误。它可以捕捉到任何可能出现的错误,并向全局抛出。
【2】finally() 用来指定不管Promise对象最后状态如何都会执行的操作。


幸福璐
70 声望12 粉丝

余生漫长,莫要慌张。


引用和评论

0 条评论