美文网首页
Promise对象

Promise对象

作者: 鹿啦啦zz | 来源:发表于2018-01-25 11:34 被阅读0次

    Promise对象

    创造一个Promise实例

    const promise = new Promise(function(resolve, reject) {//resolve,reject函数由js引擎部署
      // ... some code
      if (/* 异步操作成功 */){
        resolve(value);//状态从未完成变成成功,在异步操作成功时调用,并将异步操作的结果,作为参数传递出去
      } else {
        reject(error); //状态从未完成变成失败,在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去
      }
    });
    

    then方法

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

    promise.then(//接受两个回调函数作为参数,这两个函数都接受Promise对象传出的值作为参数。
      function(value) {//状态变为resolve时调用
      // success
    }, function(error) {//状态变为reject时调用,不建议,建议用catch
      // failure
    });
    

    Promise.prototype.then()。它的作用是为 Promise 实例添加状态改变时的回调函数。then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。
    then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。

    catch方法

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

    getJSON('/posts.json').then(function(posts) {
      // ...
    }).catch(function(error) {
      // 处理 getJSON 和 前一个回调函数运行时发生的错误
      console.log('发生错误!', error);
    });
    

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

    getJSON('/post/1.json').then(function(post) {
      return getJSON(post.commentURL);
    }).then(function(comments) {
      // some code
    }).catch(function(error) {
      // 处理前面三个Promise产生的错误
    });
    

    一般来说,不要在then方法里面定义 Reject 状态的回调函数(即then的第二个参数),总是使用catch方法。
    跟传统的try/catch代码块不同的是,如果没有使用catch方法指定错误处理的回调函数,Promise 对象抛出的错误不会传递到外层代码,即不会有任何反应。
    Promise 内部的错误不会影响到 Promise 外部的代码,通俗的说法就是“Promise 会吃掉错误”

    Promise.all()

    Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
    const p = Promise.all([p1, p2, p3]);

    p的状态由p1、p2、p3决定,分成两种情况。
    (1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
    (2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

    注意,如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法。

    const p1 = new Promise((resolve, reject) => {
      resolve('hello');
    })
    .then(result => result)
    .catch(e => e);
    
    const p2 = new Promise((resolve, reject) => {
      throw new Error('报错了');
    })
    .then(result => result)
    .catch(e => e);//返回一个resolve的promise对象
    
    Promise.all([p1, p2])
    .then(result => console.log(result))
    .catch(e => console.log(e));
    // ["hello", Error: 报错了]
    

    Promise.race()

    Promise.race方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
    const p = Promise.race([p1, p2, p3]);
    上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

    Promise.resolve()

    有时需要将现有对象转为 Promise 对象,Promise.resolve方法就起到这个作用。
    const jsPromise = Promise.resolve($.ajax('/whatever.json'));
    上面代码将 jQuery 生成的deferred对象,转为一个新的 Promise 对象。

    Promise.resolve('foo')
    // 等价于
    new Promise(resolve => resolve('foo'))
    

    需要注意的是,立即resolve的 Promise 对象,是在本轮“事件循环”(event loop)的结束时,而不是在下一轮“事件循环”的开始时。

    setTimeout(function () {
      console.log('three');
    }, 0);
    
    Promise.resolve().then(function () {
      console.log('two');
    });
    
    console.log('one');
    
    // one
    // two
    // three
    

    上面代码中,setTimeout(fn, 0)在下一轮“事件循环”开始时执行,Promise.resolve()在本轮“事件循环”结束时执行,console.log('one')则是立即执行,因此最先输出。

    Promise.reject()

    注意,Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。这一点与Promise.resolve方法不一致。

    const thenable = {
      then(resolve, reject) {
        reject('出错了');
      }
    };
    
    Promise.reject(thenable)
    .catch(e => {
      console.log(e === thenable)
    })
    // true
    

    上面代码中,Promise.reject方法的参数是一个thenable对象,执行以后,后面catch方法的参数不是reject抛出的“出错了”这个字符串,而是thenable对象。

    done()

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

    asyncFunc()
      .then(f1)
      .catch(r1)
      .then(f2)
      .done();
    

    它的实现代码相当简单。

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

    从上面代码可见,done方法的使用,可以像then方法那样用,提供fulfilled和rejected状态的回调函数,也可以不提供任何参数。但不管怎样,done都会捕捉到任何可能出现的错误,并向全局抛出。

    finally()

    finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。它与done方法的最大区别,它接受一个普通的回调函数作为参数,该函数不管怎样都必须执行。
    下面是一个例子,服务器使用 Promise 处理请求,然后使用finally方法关掉服务器。

    server.listen(0)
      .then(function () {
        // run test
      })
      .finally(server.stop);
    

    它的实现也很简单。

    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 })
      );
    };
    

    上面代码中,不管前面的 Promise 是fulfilled还是rejected,都会执行回调函数callback。

    相关文章

      网友评论

          本文标题:Promise对象

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