Promise的回调函数传入另一个Promise的疑惑?

在阮一峰老师的《ES6标准入门》里面看到关于Promise的一个代码,让我很费解:

var p1 = new Promise(function (resolve, reject) {
    setTimeout(() => reject(new Error('fail')), 3000)
})
var p2 = new Promise(function (resolve, reject) {
    setTimeout(() => resolve(p1), 1000)
})
p2
.then(result => console.log(result))
.catch(error => console.log(error))

上述代码的输出结果是:Error: fail
而书上的表述是:

上面代码中,p1是一个Promise,3秒之后变为rejected。p2的状态在1秒之后改变,resolve方法返回的是p1。此时,由于p2返回的是另一个
Promise,所以后面的then语句都变成针对后者(p1)。又过了2秒,p1变为rejected,导致触发catch方法指定的回调函数。

这个就让我觉得很费解了。

  • 为什么p2后跟的then针对的是p1而不是p2本身呢?

  • p2中resolve(p1)这个到底发生了什么呢?为什么说“resolve方法返回的是p1”?resolve方法在此处不是应该是.then(result => console.log(result))吗?它返回undefined的呀?

  • 如果我就是想在控制台中打印出p1这个对象本身,即可以查看p1的属性等等,那么p2的then的回调函数代码应该怎么写呢?

阅读 2.1k
评论 2017-09-02 提问
    4 个回答
    will
    • 2.5k

    首先,从简单的 Promise 理解开始。先别扯 Promise 嵌套的问题。因为最朴素的 Promise 概念你就弄错了。

    var p = new Promise(function(resolve, reject) {
      resolve(1);
    });
    
    var cb = function(data) {
      console.log(data);
    };
    
    p.then(cb); // cb函数 和 上面的 resolve 不是一个东西!不是!
    

    看起来 Promise 里的 resolve 方法就像是 then 方法传递过来的这个回掉函数?当然不是!resolve 是指用一个值来 完成 这个 promise,只有 promise resolve了,then方法注册的回掉才会被执行。同理,即使没人关心你这个 promise 是否会被 resolve,没有人用 then 注册回掉函数,resolve 照样可以正常执行。

    为什么p2后跟的then针对的是p1而不是p2本身呢?

    为什么?标准就是这样规定的啊!

    标准规定,如果你用普通对象来 resolve 一个 promise,这个promise就立马拿着这个值然后变成 resolved 状态,如果你用一个 thenable 的对象,就是一个promise对象 来 resolve 另一个 promise,这个 promise 就会自动关联起来!

    var p1 = new Promise(function(resolve) {
      setTimeout(function(){
        resolve(1);
      }, 1000);
    });
    
    var p2 = new Promise(function(resolve, reject) {
      resolve(p1);
      // 等价于
      p1.then(resolve).catch(reject);
    });
    // 标准就是这样规定的,这才是 promise 的价值所在,否则和普通的callback有什么区别?

    要在 p2.then 里拿到 p1 ?

    那你别用一个 promise 对象作为值来 resolve p2 啊!

    话说你又是为什么要在 then 里拿到 p1呢?拿到p1你又能干什么的?还不是调用.then 么?
    话说你又是为什么要在 then 里拿到 p1呢?拿到p1你又能干什么的?还不是调用.then 么?
    话说你又是为什么要在 then 里拿到 p1呢?拿到p1你又能干什么的?还不是调用.then 么?

    不存在这种需求的,没道理要这样作,如果要,那你这样啊:

    resolve([p1])

    p2.then(([p1]) => {
    // p1
    })

    评论 赞赏