【问题标题】:Implementing a verbose sleep function using a chain of Promises使用 Promises 链实现详细的睡眠功能
【发布时间】:2019-05-28 10:34:02
【问题描述】:

我正在尝试使用 JavaScript 中的 Promises 实现睡眠功能。

function sleep(ms) {

  var begin = new Promise(resolve => {
    console.log("Sleep function called for " + ms + " ms\n")
  });

  return new Promise(resolve => setTimeout(resolve, ms))
    .then(() => console.log("Sleep done!" ));

}

它有效。但是,

function sleep(ms) {

  var begin = new Promise(resolve => {
    console.log("Sleep function called for " + ms + " ms\n")
  });

  return begin.then(resolve => setTimeout(resolve, ms))
    .then(() => console.log("Sleep done!" ));

}

没有,而是挂起!是什么赋予了?

更新:我真正想做的是把它写成一系列的 Promise 调用。

function sleep(ms) { 
    var beginAnnounce = new Promise(...);
    var goSleep = new Promise (...);
    var endAnnounce = new Promise...);

    return beginAnnounce.then(goSleep).then(endAnnounce());

}

【问题讨论】:

  • begin Promise 永远不会解决,因为你永远不会调用它的 resolve 方法
  • 那么,我必须在第二个代码 sn-p 中进行哪些更改?
  • "...和可能的竞争条件" - 想解释一下这个假设吗?
  • 调用begin的初始Promise中构造的resolve参数
  • 请帮助提供实际代码。

标签: javascript promise sleep chaining


【解决方案1】:

如果您想组合两个 Promise,您可以在传递给第一个 Promise 的 Promise.prototype.then 的回调中返回第二个 Promise。

看看下面的代码:

const sleep = ms => () => new Promise((resolve, reject) => window.setTimeout(resolve, ms));

Promise.resolve()
.then(() => { console.log('A1');})
.then(sleep(2000))
.then(() => {console.log('A2');});

Promise.resolve()
.then(() => {console.log('B1');})
.then(sleep(1000))
.then(() => {console.log('B2');});

sleep 函数是一个高阶函数,它返回另一个返回承诺的函数。这个承诺在对Window.setTimeout 的调用中得到解决,由传递给sleepms 参数化。

如您所见,执行是交错的,您将看到第二个 promise 的语句 console.log('B2') 的日志输出,然后是第一个 promise 的 console.log('A2'); 的输出。

【讨论】:

  • 知道了!现在,我将如何传递 ms 值以在链中休眠?
  • 不太确定我是否理解。你想动态决定回调到.then的ms值吗?
  • 没关系:代码是包含三个或两个承诺链吗?只是为了我的清楚。
  • 这真的很简单:你只需立即调用sleep(ms)返回的函数:p.then((result) => { const ms = /*calculate duration*/; return sleep(ms)();});,其中p是你的承诺。
  • 关于承诺计数的问题有点棘手。从技术上讲,Promise.prototype.then 从它被调用的 Promise 中创建了一个新的 Promise,但它们是单独解决的,所以它们应该单独计算(MDN documentation 也通过调用 .then 来暗示这一点 composition 功能)。 inner 承诺似乎是隐式组合的,非承诺返回值包含在承诺中。因此,每个组合应该包含三个承诺。
【解决方案2】:

在第二个sn-p中,需要立即解析begin

var begin = new Promise(resolve => {
  console.log("Sleep function called for " + ms + " ms\n")
  resolve()
})

它在第一个 sn-p 中起作用的原因是因为您从不依赖 begin 来完成,您只需在那里记录开始。但这不是你想要的方式。立即解决的 Promise 毫无意义(无论如何都不适用于您的用例)。所以你应该做类似的事情:

function sleep(ms) {
  console.log("Sleep function called for " + ms + " ms\n")

  return new Promise(resolve => {
    setTimeout(() => {
      console.log("Sleep done!")
      resolve()
    }, ms)
  })
}

【讨论】:

  • 但是您的代码与我在第一个 sn-p 中的代码或多或少相同。是吗?
  • 我不会说。存在功能上的差异。你仍然需要解决你返回的承诺。我的意思是,如果你只是想console.log 也没关系,但是,承诺有什么意义呢?如果您要使用 sleepawait 来实现延迟,它将无法正常工作。另一个区别是您正在创建无用的begin 承诺
  • 查看我对 OP 的“更新”。我正在尝试的是通过实践来建立一系列承诺(尽管在这里它是一种矫枉过正)。这甚至可能吗?
  • 同样,这取决于您希望如何使用sleep 函数。如果您只想调用它并让它记录“开始”->“睡眠”->“结束”,那么您根本不需要承诺,您可以使用普通的 ol'setTimeout。否则,你仍然不需要一个以上的承诺。你只能退回一个。因此,即使您想延迟 beginAnnounce 消息,您也可以使用 setTimeout 来实现,endAnnounce 也是如此
  • 我还建议您继续更改问题标题。它与 Promise 竞争条件无关,我想这就是你得到反对票的原因。我会选择“帮助实现sleep 函数”或类似的内容。
猜你喜欢
  • 2016-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-23
  • 2011-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多