美文网首页
Promise学习笔记

Promise学习笔记

作者: 围观工程师 | 来源:发表于2018-06-19 10:56 被阅读0次

    原文地址

    resolve一个promise实例会发生什么?

    const p1 = new Promise(function (resolve, reject) {
      // ...
    });
    
    const p2 = new Promise(function (resolve, reject) {
      // ...
      resolve(p1);
    })
    

    如果把p1当作p2 resolve方法的参数,那么p1的状态就会传递给p2,也就是说,p1的状态决定了p2的状态。如果p1的状态是pending,那么p2的回调函数就会等待p1的状态改变;如果p1的状态已经是resolved或者rejected,那么p2的回调函数将会立刻执行。

    resolve或reject并不会终结 Promise 的参数函数的执行

    new Promise((resolve, reject) => {
      resolve(1);
      console.log(2);
    }).then(r => {
      console.log(r);
    });
    // 2
    // 1
    

    上面代码中,调用resolve(1)以后,后面的console.log(2)还是会执行,并且会首先打印出来。这是因为立即 resolved 的 Promise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。

    Promise.prototype.then()

    then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。

    采用链式的then,可以指定一组按照次序调用的回调函数。这时,前一个回调函数,有可能返回的还是一个Promise对象(即有异步操作),这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用。

    getJSON("/post/1.json").then(function(post) {
      return getJSON(post.commentURL);
    }).then(function funcA(comments) {
      console.log("resolved: ", comments);
    }, function funcB(err){
      console.log("rejected: ", err);
    });
    

    Promise 会吃掉错误

    const someAsyncThing = function() {
      return new Promise(function(resolve, reject) {
        // 下面一行会报错,因为x没有声明
        resolve(x + 2);
      });
    };
    
    someAsyncThing().then(function() {
      console.log('everything is great');
    });
    
    setTimeout(() => { console.log(123) }, 2000);
    // Uncaught (in promise) ReferenceError: x is not defined
    // 123
    

    上面代码中,someAsyncThing函数产生的 Promise 对象,内部有语法错误。浏览器运行到这一行,会打印出错误提示ReferenceError: x is not defined,但是不会退出进程、终止脚本执行,2 秒之后还是会输出123。这就是说,Promise 内部的错误不会影响到 Promise 外部的代码,通俗的说法就是“Promise 会吃掉错误”。

    这个脚本放在服务器执行,退出码就是0(即表示执行成功)。不过,Node 有一个unhandledRejection事件,专门监听未捕获的reject错误,上面的脚本会触发这个事件的监听函数,可以在监听函数里面抛出错误。

    process.on('unhandledRejection', function (err, p) {
      throw err;
    });
    

    上面代码中,unhandledRejection事件的监听函数有两个参数,第一个是错误对象,第二个是报错的 Promise 实例,它可以用来了解发生错误的环境信息。

    注意,Node 有计划在未来废除unhandledRejection事件。如果 Promise 内部有未捕获的错误,会直接终止进程,并且进程的退出码不为 0。

    Promise.race()

    只要有一个实例率先改变状态,Promise.race()的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给Promise.race()的回调函数。

    const p = Promise.race([
      fetch('/resource-that-may-take-a-while'),
      new Promise(function (resolve, reject) {
        setTimeout(() => reject(new Error('request timeout')), 5000)
      })
    ]);
    
    p
    .then(console.log)
    .catch(console.error);
    

    上面代码中,如果 5 秒之内fetch方法无法返回结果,变量p的状态就会变为rejected,从而触发catch方法指定的回调函数。

    Promise.resolve()

    参数是一个thenable对象

    thenable对象指的是具有then方法的对象。

    Promise.resolve方法会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then方法。

    let thenable = {
      then: function(resolve, reject) {
        setTimeout(() => {
          resolve(42);
        }, 3000);
      }
    };
    
    let p1 = Promise.resolve(thenable);
    p1.then(function(value) {
      console.log(value);  // 42
    });
    

    上面代码中,thenable对象的then方法的resolve参数执行后,对象p1的状态就变为resolved,从而立即执行最后那个then方法指定的回调函数,输出 42。

    Promise.resolve()与setTimeout

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

    何为“立即resolve的Promise对象”?

    1. Promise.resolve()参数为空,或者为thenable对象
    2. 当Promise.resolve()参数为thenable对象时,且then属性函数里的resolve参数立即执行而不是等待某些异步操作的结果,如下:
    setTimeout(function () {
      console.log('settimeout');
    }, 0);
    
    Promise.resolve({
      then (resolve, reject) {
        resolve('1')
      }
    }).then(function () {
      console.log('promise');
    });
    
    1. 当Promise.resolve()参数为Promise的实例时,且其resolve参数立即执行而不是等待某些异步操作的结果,如下:
    setTimeout(function () {
      console.log('settimeout');
    }, 0);
    
    let p = new Promise((resolve, reject) => {
      resolve(1)
    })
    
    Promise.resolve(p).then(function () {
      console.log('promise');
    });
    

    Promise.reject()

    Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。

    注意,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对象。

    Promise.try()

    无论同步还是异步,都在then中处理结果,在catch中捕获错误。

    目前官方还未实现,两种代替方法:

    const f = () => console.log('now');
    (async () => f())();
    console.log('next');
    // now
    // next
    
    const f = () => console.log('now');
    (
      () => new Promise(
        resolve => resolve(f())
      )
    )();
    console.log('next');
    // now
    // next
    

    相关文章

      网友评论

          本文标题:Promise学习笔记

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