关于这两个伟大的来源:NZakas - Returning Promises in Promise ChainsMDN Promises,我想问以下问题:

每次我们从promise 履行处理程序返回一个值时,该值如何传递给同一处理程序返回的新promise ?

例如,

let p1 = new Promise(function(resolve, reject) {
    resolve(42);
});

let p2 = new Promise(function(resolve, reject) {
    resolve(43);
});

let p3 = p1.then(function(value) {
    // first fulfillment handler
    console.log(value);     // 42
    return p2;
});

p3.then(function(value) {
    // second fulfillment handler
    console.log(value);     // 43
});

在这个例子中,p2是一个promise .p3也是源于p1的履行处理程序的promise .然而p2 !== p3.相反,p2会神奇地变成43(如何?)然后将该值传递给p3的实现处理程序.甚至这里的句子也令人困惑.

你能解释一下这里到底发生了什么吗?我完全搞不懂这个概念.

推荐答案

假设抛出then()次回调失败地拒绝了结果promise ,而从then()次回调返回则实现了结果promise 的成功值.

let p2 = p1.then(() => {
  throw new Error('lol')
})
// p2 was rejected with Error('lol')

let p3 = p1.then(() => {
  return 42
})
// p3 was fulfilled with 42

但有时,即使在续集里,我们也不知道自己是否成功了.我们需要更多的时间.

return checkCache().then(cachedValue => {
  if (cachedValue) {
    return cachedValue
  }

  // I want to do some async work here
})

然而,如果我在那里做异步工作,到returnthrow就太晚了,不是吗?

return checkCache().then(cachedValue => {
  if (cachedValue) {
    return cachedValue
  }

  fetchData().then(fetchedValue => {
    // Doesn’t make sense: it’s too late to return from outer function by now.
    // What do we do?

    // return fetchedValue
  })
})

这就是为什么如果你做不到,promise 就没有用处.

这并不意味着在你的例子中p2会是become p3.它们是不同的promise 对象.然而,如果从then()返回p2,产生p3,你就是说“I want 101 to resolve to whatever 100 resolves, whether it succeeds or fails”.

对于how来说,这种情况是特定于实现的.在内部,你可以认为then()是创造一个新的promise .实现将能够在任何时候满足或拒绝它.通常,当您返回时,它会自动完成或拒绝:

// Warning: this is just an illustration
// and not a real implementation code.
// For example, it completely ignores
// the second then() argument for clarity,
// and completely ignores the Promises/A+
// requirement that continuations are
// run asynchronously.

then(callback) {
  // Save these so we can manipulate
  // the returned Promise when we are ready
  let resolve, reject

  // Imagine this._onFulfilled is an internal
  // queue of code to run after current Promise resolves.
  this._onFulfilled.push(() => {
    let result, error, succeeded
    try {
      // Call your callback!
      result = callback(this._result)
      succeeded = true
    } catch (err) {
      error = err
      succeeded = false
    }

    if (succeeded) {
      // If your callback returned a value,
      // fulfill the returned Promise to it
      resolve(result)
    } else {
      // If your callback threw an error,
      // reject the returned Promise with it
      reject(error)
    }
  })

  // then() returns a Promise
  return new Promise((_resolve, _reject) => {
    resolve = _resolve
    reject = _reject
  })
}

同样,这是非常伪的代码,但展示了如何在Promise实现中实现then().

如果我们想添加对解析promise 的支持,我们只需要修改代码,以便在传递给then()callback返回promise 时有一个特殊分支:

    if (succeeded) {
      // If your callback returned a value,
      // resolve the returned Promise to it...
      if (typeof result.then === 'function') {
        // ...unless it is a Promise itself,
        // in which case we just pass our internal
        // resolve and reject to then() of that Promise
        result.then(resolve, reject)
      } else {
        resolve(result)
      }
    } else {
      // If your callback threw an error,
      // reject the returned Promise with it
      reject(error)
    }
  })

让我再次澄清一下,这不是一个实际的promise 实现,存在很大的漏洞和不兼容.不过,它应该让您直观地了解Promise库如何实现对Promise的解析.在你对这个 idea 感到满意之后,我建议你看看实际的promise 是如何实现的.

Node.js相关问答推荐

无法从ejs Web应用程序中的正文中提取数据

MongoDB-如何验证Document字段以仅允许特定的文件扩展名?

MongoDB上的updateOne和findOneAndUpdate在Node.js中无法正常工作

findoneandupdate()方法更新数据库,但其响应在请求中返回为null

Mongoose抱怨说,整数是数字,而不是整数

Node.js分页返回空数组

我的Node.js应用程序没有将Mongoose方法findByIdAndDelete作为函数进行检测

即使卷已设置,Docker Nodemon 也不会热重载

如果我在父文件夹中运行,子进程生成不起作用

我应该如何解决这个 Angular node 包模块依赖冲突?

简单的 Node js 程序但执行顺序似乎不同?

Mongodb聚合传递一个匹配的数组和一个不匹配的数组

使用 mongoose 查找过go 7 天的注册用户总数

node.js 中 res.setHeader 和 res.header 的区别

Node.js、Cygwin 和 Socket.io 走进一家wine 吧……Node.js 抛出 ENOBUFS,所有人都死了

什么使用/尊重 .node-version 文件?

容器之间的 Docker HTTP 请求

如何使用 Node.js 将 base64 编码图像(字符串)直接上传到 Google Cloud Storage 存储桶?

我可以有条件地将 where() 子句添加到我的 knex 查询吗?

Socket.IO 连接用户数