美文网首页工作生活
ES6 深入了解Promise对象

ES6 深入了解Promise对象

作者: 萘小蒽 | 来源:发表于2019-07-07 23:17 被阅读0次

    Promise对象的含义

    所谓的Promise就是一个对象,用来传递异步操作的消息,它代表某个未来才会知道结果的事件(异步操作)。

    Promise对象特点

    1. 该对象的状态不受外界影响。
    Promise代表一个异步操作,它有三种状态:
    Pending (进行中)、Resolved(已完成)、Rejected (已失败)
    只有异步操作的结果可以决定当前是那一种状态,任何其他操作都不能改变这个状态。这也是 “Promise” 这个名字的由来。

    2. 一旦状态改变就不会再变,任何操作都能得到这个结果。
    Promise对象的状态改变只有两种可能
    Pending变为Resolved或者从 Pending变为Rejected 。只要其中一个发生,状态就凝固不会再变,一直保持这个结果。

    Promise对象缺点

    • 首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。
    • 其次,如果不设置回调函数,Promise内部抛出的错误不会反应到外部。
    • 再者,当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

    基本用法

    Promise对象是一个构造函数,用来生成Promise实例。

    var promise = new Promise(function(resolve,reject){
       //逻辑代码
        if(/*异步成功*/){
           resolve(value);
         } else{
          reject(error)
        }
    });
    

    Promise构造函数接受一个函数作为参数,改函数的两个参数分别是resolvereject,它们是两个函数,由javaScript引擎提供,不用自己部署。

    • resolve函数的作用,将Promise函数的状态从 未完成 变成 成功(从Pending变为Resolved),在异步操作成功时调用,并将异步操作的结果作为参数传递出去;
    • reject函数的作用,将Promise函数的状态从 未完成 变成 失败(从Pending变为Rejected),在异步操作失败时调用,并将异步操作报出的错误作为参数传递出去;

    Promise实例生成以后,可以用then方法分别指定Resolved状态和Rejected状态的回调函数

    promise.then(function(value){
           //success
     },function(value){
           //failure
     })
    

    then方法可以接受两个回调函数作为参数。第一个函数是Promise对象的状态变为Resolved时调用,第二个是变为Rejected时调用。第二个参数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。

    function timeout(ms){
      return new Promise((resolv,reject)=>{
       setTimeout(resolve,ms,'done')
      });
    }
    timeout(100).then(function(value){
       console.log(value)
    })
    

    ↑上面代码timeout返回一个Promise实例,表示一段时间以后才会发生的结果。过了指定的时间(ms)以后,Promise实例的状态变为Resolved,就会触发then方法绑定的回调函数。


    function loadImageAsync(url){
        return new Promise(function(resolve,reject){
           var image = new Image();
           image.onload = function(){
                resolve(image);
           };
           image.onerror = function(){
               reject(new Error("无法加载图片,地址:" + url ));
          }; 
          image.src = url;
       })
    }
    

    ↑上面是一个异步加载图片的例子.


    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.readyState !==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.error('出错了',error);
    });
    

    上面的代码中,getJSON是对XMLHttpRequest对象的封装,用于发出一个针对JSON数据的HTTP请求,并返回一个Promise对象。需要注意的是,在getJson内部,resolve函数和reject函数调用时带有参数。

    Promise.prototype.then();

    Promise的实例具有then方法。也就是说,then方法是定义在原型对象Promise.prototype上的。
    它的作用是为Promise的实例添加状态改变时的回调函数。
    then方法返回的是一个新的Promise实例(注意,不是原来那个Promise的实例)

    var p1 = new Promise(function(resolve,reject){
    });
    var p2 = p1.then(function(){})
    p1
    //Promise {<pending>}
    p2
    //Promise {<pending>}
    p1 == p2
    //false
    

    ↑上面可以看到p2是then方法返回的新的Promise实例,因此可以采用链式写法,即then方法后面再调用then方法。

    getJSON("/posts.json").then(function(json){
        return  json.post;
    }).then(function(post){
        //....
    });
    

    ↑上面的代码使用then方法一次指定了两个回调函数。第一个回调函数完成以后,会将返回结果作为参数传入第二个回调函数。

    Promise.prototype.catch();

    Promise.prototype.catch()Promise.prototype.then(null,reject)的别名,用于指定发生错误时的回调函数。

    getJSON("/posts.json").then(function(json){
        return  json.post;
    }).then(post=> {
        //....
    }).cath(err=>{
      /....
    })
    

    如果异步过程中抛出错误,机会被catch方法指定的回调函数所捕获。(条件是Promise状态还未变成resolved,否则抛出的错是无效的。)

    var p1 = new Promise(function(resilve,reject){
       throw new Error('test')
    });
    p1.then(success=>{}).catch(err=>{console.log(err)})
     // Error: test
    
    var p2 = new Promise(function(resilve,reject){
       resilve('success');
       throw new Error('test')
    });
    p2.then(suc=>{console.log(suc)}).catch(err=>{console.log(err)})
    //success
    

    Promise对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获位置,也就是说错误总是会被下一个catch语句捕获。

    getJSON("/posts.json").then(function(json){
        return  json.post;
    }).then(post=> {
        //....
    }).cath(err=>{
     //处理前面三个Promise产生的错误
    })
    

    正规的写法不要在then方法中写rejected的状态回调函数(then的第二个参数),而是使用catch方法。

    catch方法返回的也是一个 Promise实例,所以在 Promise方法在未抛出错误的时候,catch方法后面还可以继续调用then方法。

    Promise.all();

    Promise.all方法用于将多个Promise实例包装成一个新的Promise实例。

    var p = Promise.all([p1, p2, p3]);
    

    Promise.all接受一个数组作为参数,如果非数组,就会先调用Promise.resolve方法,将参数转为Promise实例,再进一步处理。

    Promise.all方法的参数不一定是数组,但必须具有Iterator接口,且返回的每个成员都是Promise.实例。

    上面的代码p的状态由p1, p2, p3决定,分两种情况。

    1. 只有p1, p2, p3的状态都变成Fulfilledp的状态才会变成Fulfilled,此时p1, p2, p3的返回值组成一个数组,传递给你p的回调函数。
    2. 只要 p1, p2, p3中的状态有一个变成Rejected,此时第一个被Rejected实例返回值会传递给p的回调函数。

    Promise.race();

    Promise.all();同样是将多个Promise实例包装成一个新的Promise实例。

    var p = Promise.race([p1, p2, p3]);
    

    Promise.race的参数规则和上面讲到的Promise.all方法一样。

    p的状态规则不一样,只要p1, p2, p3的状态中有一个实例率先改变,p的状态也跟着改变。

    Promise.resolve();

    有时我们需要把现有对象转为Promise对象,Promise.resolve方法就可以做到。

    var jsPromise = Promise.resolve($.ajax('/whatever.json'));
    

    上面的代码将jQuery生成的deferred对象转为新的Promise对象。

    Promise.resolve('foo');
    

    ↑上面等价于下面的写法;

    new Promise(resolve=>resolve('foo'))
    

    Promise.reject();

    Promise.reject(reason) 也返回一个新的Promise实例,状态为rejected,它的的参数reason会被传递给实例的回调函数。

    var p = Promise('出错了!!');
    

    ↑等同于↓

    var p = new Promise((resolve,reject)=>reject('出错了!!'));
    p.then(null,(s)=>{console.log(s)})
    //出错了!!
    

    相关文章

      网友评论

        本文标题:ES6 深入了解Promise对象

        本文链接:https://www.haomeiwen.com/subject/lxxchctx.html