Javascript充满好奇心 [英] Javascript Promises curiosity

查看:27
本文介绍了Javascript充满好奇心的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我调用此Promise时,输出与函数调用序列不匹配. .then .catch 之前,即使之后调用了 .then 的承诺.是什么原因呢?

When I call this promise, the output does not match with the sequence of function calls. The .then comes before the .catch, even though the promise with .then was being called after. What is the reason for that?

const verifier = (a, b) =>
  new Promise((resolve, reject) => (a > b ? resolve(true) : reject(false)));

verifier(3, 4)
  .then((response) => console.log("response: ", response))
  .catch((error) => console.log("error: ", error));

verifier(5, 4)
  .then((response) => console.log("response: ", response))
  .catch((error) => console.log("error: ", error));

输出

node promises.js
response: true
error: false

推荐答案

这是个很酷的问题.

执行此操作时:

verifier(3,4).then(...)

返回一个新的Promise,在新拒绝的Promise可以运行随后的 .catch()处理程序之前,它需要另一个循环返回到事件循环.这个额外的循环给出了下一个序列:

that returns a new promise which requires another cycle back to the event loop before that newly rejected promise can run the .catch() handler that follows. That extra cycle gives the next sequence:

verifier(5,4).then(...)

在前一行的 .catch()之前运行其 .then()处理程序的机会,因为它已经在 .catch()处理程序进入第一个队列,然后按FIFO顺序从队列中运行项目.

a chance to run its .then() handler before the previous line's .catch() because it was already in the queue before the .catch() handler from the first one gets in the queue and items are run from the queue in FIFO order.

请注意,如果您使用 .then(f1,f2)形式代替 .then().catch(),则当您使用期望它是因为没有额外的承诺,因此也没有额外的滴答声:

Note, that if you use the .then(f1, f2) form in place of the .then().catch(), it does run when you expect it to because there's no additional promise and thus no additional tick involved:

const verifier = (a, b) =>
  new Promise((resolve, reject) => (a > b ? resolve(true) : reject(false)));

verifier(3, 4)
  .then((response) => console.log("response (3,4): ", response),
        (error) => console.log("error (3,4): ", error)
  );

verifier(5, 4)
  .then((response) => console.log("response (5,4): ", response))
  .catch((error) => console.log("error (5,4): ", error));

请注意,我还标记了所有消息,以便您查看它们来自哪个 verifier()调用,从而使读取输出变得更加容易.

Note, I also labeled all the messages so you can see which verifier() call they come from which makes it a lot easier to read the output.

ES6 Promise回调顺序规范和更详细的说明

ES6规范告诉我们,承诺工作"(因为它从 .then() .catch()调用回调)是基于将它们插入作业队列的时间而按FIFO顺序运行的.它没有专门命名FIFO,但指定在队列末尾插入新作业,并从队列的开头运行作业.这实现了FIFO排序.

The ES6 spec tells us that promise "jobs" (as it calls a callback from a .then() or .catch()) are run in FIFO order based on when they are inserted into the job queue. It doesn't specifically name FIFO, but it specifies that new jobs are inserted at the end of the queue and jobs are run from the beginning of the queue. That implements FIFO ordering.

PerformPromiseThen (从执行回调> .then())将导致 EnqueueJob 解决方案或拒绝处理程序被安排为实际运行的方式.EnqueueJob指定将挂起的作业添加到作业队列的后面.然后 NextJob 操作从前面拉该项目的队列.这样可以确保在服务Promise作业队列中的作业时FIFO顺序.

PerformPromiseThen (which executes the callback from .then()) will lead to EnqueueJob which is how the resolve or reject handler gets scheduled to be actually run. EnqueueJob specifies that the pending job is added at the back of the job queue. Then the NextJob operation pulls the item from the front of the queue. This ensures FIFO order in servicing jobs from the Promise job queue.

因此,在原始问题的示例中,我们获得了 verifier(3,4) Promise和 verifier(5,4) Promise的回调因为它们都完成了原来的承诺,所以按运行顺序进入作业队列.然后,当解释器返回事件循环时,它首先执行 verifier(3,4)作业.那个承诺被拒绝了,在 verifier(3,4).then(...)中没有回调.因此,它所做的就是拒绝 verifier(3,4).then(...)返回并导致 verifier(3,4).then(...).catch(...)处理程序,将其插入到jobQueue中.

So, in the example in the original question, we get the callbacks for the verifier(3,4) promise and the verifier(5,4) promise inserted into the job queue in the order they were run because both those original promises are done. Then, when the interpreter gets back to the event loop, it first picks up the verifier(3,4) job. That promise is rejected and there's no callback for that in the verifier(3,4).then(...). So, what it does is reject the promise that verifier(3,4).then(...) returned and that causes the verifier(3,4).then(...).catch(...) handler to be inserted into the jobQueue.

然后,它返回到事件循环,并且从jobQueue中提取的下一个作业是 verifier(5,4)作业.它具有一个已解决的Promise和一个已解决的处理程序,因此它将调用该处理程序.这将导致显示 response(5,4):输出.

Then, it goes back to the event loop and the next job it pulls from the jobQueue is the verifier(5, 4) job. That has a resolved promise and a resolve handler so it calls that handler. This causes the response (5,4): output to be shown.

然后,它返回事件循环,并且从jobQueue中提取的下一个作业是 verifier(3,4).then(...).catch(...)运行它的作业,这会导致显示 error(3,4)输出.

Then, it goes back to the event loop and the next job it pulls from the jobQueue is the verifier(3,4).then(...).catch(...) job where it runs that and this causes the error (3,4) output to be shown.

这是因为第一条链中的 .catch()在其链中比第二条链中的 .then()更深一层的承诺水平,导致了排序你报告了.而且,这是因为承诺链是通过作业队列以FIFO顺序从一个级别遍历到下一个级别,而不是同步进行的.

It's because the .catch() in the 1st chain is one promise level deeper in its chain than the .then() in the 2nd chain that causes the ordering you reported. And, it's because promise chains are traversed from one level to the next via the job queue in FIFO order, not synchronously.

关于依赖此级别的计划明细的一般建议

一般来说,我尝试编写不依赖于这种详细定时知识水平的代码.尽管它很好奇并且有时有用,但它是脆弱的代码,因为对代码的简单看似无害的更改可能会导致相对时间的更改.因此,如果在这样的两个链之间,计时至关重要,那么我宁愿以强制计时的方式编写代码,也不要依赖这种详细的理解.

FYI, in general, I try to write code that does not depend upon this level of detailed timing knowledge. While it's curious and occasionally useful to understand, it is fragile code as a simple seemingly innocuous change to the code can lead to a change in the relative timing. So, if timing is critical between two chains like this, then I would rather write the code in a way that forces the timing the way I want it rather than rely on this level of detailed understanding.

这篇关于Javascript充满好奇心的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆