【问题标题】:why callback inside then() is executed via job queue in JS为什么 then() 中的回调是通过 JS 中的作业队列执行的
【发布时间】:2020-03-12 06:01:21
【问题描述】:

我是 JS 新手,正在学习 Promises。我面临的困惑是 then() 中的回调被推入作业队列。这是一个例子:

 let promise = new Promise((resolve, reject) => {
       resolve(setTimeout(()=>console.log('Done'),2000))
    })
    .then((data) => {           
      data;
    })

所以,我们有一个可以通过 console.log('Done') 解决的承诺。之后,console.log('Done') 被传递给 then() 并且 then() 中的回调被传递给作业队列。为什么?我们从异步 setTimeout 中得到数据后,为什么需要将 then() 中的回调传递给作业队列?

编辑

假设我们有以下代码:

let promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('foo');
    }, 2000);
})
.then((data) => {
    console.log(`resolved value: ${data}`);
    return 'bar';
})

上面的代码是这样工作的吗?一、代码执行时,JS引擎在里面遇到promise和setTimeout。然后,将 setTimeout 推送到 Web Api 中,然后 JS 引擎继续执行代码并遇到 then 及其回调。然后 then 的回调被推入作业队列并等待直到 promise 被解决。那是对的吗?

【问题讨论】:

  • 你想完成什么?
  • setTimeout() 返回一个 timerID,然后在稍后的某个时间执行它的计时器回调。因此,这意味着您正在使用 timerID 作为已解决的值立即解决承诺,并且计时器回调在 2 秒后被调用。同时,由于 promise 被解决,.then() 处理程序被调用。所有.then() 处理程序在未来的滴答声中执行,而不是同步执行。这就是 promise 规范的编写方式。
  • 您的示例没有任何意义,因为超时与(立即!)承诺解决方案无关。如果这只是一个错误,而您真的想问名义上的问题,请参阅What is the intention behind clause 2.2.4 of Promise/A+ spec?
  • @Bergi,您好,感谢您的好心 cmets,我只是想了解为什么 then() 的回调是通过作业队列执行的。回调的原因是不是真的可以是异步的,例如.then((data) => { return setTimeout(data); })。如果是这样,那么如果我们不使用异步代码而只使用 .then((data) => { data; }) 那么通过作业队列执行此回调有什么意义,因为它只是同步的
  • @Dickens 不知道,我认为这仍然是一个未解决的问题。为资源的声誉建立个人指标需要时间……诸如拍手/投票、cmets 甚至拼写质量之类的想法都可以作为指标。

标签: javascript promise


【解决方案1】:

promise 被定义为 一个对象,它具有 一个函数作为属性的值,然后:

那么(fulfilledHandler、errorHandler、progressHandler)

这个函数应该返回一个新的承诺,当 给定的fulfilledHandler 或errorHandler 回调已完成。这 允许将 Promise 操作链接在一起。返回的值 来自回调处理程序的是返回的履行值 承诺。如果回调抛出错误,返回的承诺将是 移动到失败状态。

换句话说,then 不是附加回调的机制;它是一种将转换应用于 Promise 并从该转换中产生新 Promise 的机制。

【讨论】:

  • progressHandler?你从哪里得到的?
【解决方案2】:

我不确定这段代码的行为是否如您所想。

let promise = new Promise((resolve, reject) => {
    resolve(setTimeout(()=>console.log('Done'),2000))
})
.then((data) => {
    data;
})

这个承诺会立即setTimeout 调用的结果来解决。这可以通过在then 回调中添加日志来证明:

.then((data) => {
    console.log('data', data);
    data;
})

这个例子可能会有所帮助:

let promise = new Promise((resolve, reject) => {
    console.log('one');
    setTimeout(() => {
        console.log('three');
        resolve('foo');
        console.log('four');
    }, 2000);
    console.log('two');
})
.then((data) => {
    console.log(`resolved value: ${data}`);
    return 'bar';
})

promise.then(data => console.log(`resolved value: ${data}`));

【讨论】:

  • 嘿,安迪,感谢您的友好回答,我只是想了解为什么 then() 的回调被传递到作业队列中。从那以后()的回调只有在我们从异步操作中获取数据后才会执行。在获取数据后,我从逻辑上无法得到将 then() 的回调传递到作业队列的原因
  • 拜托我真的需要你的帮助((
  • 我猜第一个原因是它在规范中 - ecma-international.org/ecma-262/6.0/#sec-promise-objects。对我来说,这比更改当前调用堆栈更有意义,特别是因为我们只是传递一个函数,而不是调用它。您的回调也可能是异步的 - 在这种情况下立即执行是否有意义?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-09
  • 1970-01-01
相关资源
最近更新 更多