Nodejs承诺解决意外行为

发布于 2025-01-30 11:47:15 字数 758 浏览 4 评论 0 原文

我有以下代码,该代码无法正常工作。

const bar = () => console.log('bar')
const baz = () => console.log('baz')
const myPromise = new Promise((resolve, reject) =>
    resolve('should be right after baz, before bar')
);
const foo = () => {
    console.log('foo')
    setTimeout(bar, 0)
    myPromise.then(resolve => console.log(resolve))
    baz()
}

foo()
console.log('before bar')

结果:

foo
baz
before bar
should be right after baz, before bar
bar

根据

承诺在当前函数之后立即执行当前函数结束之前解决。

因此,我希望在 foo()结束后,在bar baz之后,在baz之后,在 console.log('ther bar'之前)。 有人可以解释为什么不这样做吗?

I have the following code, which does not work as I expect.

const bar = () => console.log('bar')
const baz = () => console.log('baz')
const myPromise = new Promise((resolve, reject) =>
    resolve('should be right after baz, before bar')
);
const foo = () => {
    console.log('foo')
    setTimeout(bar, 0)
    myPromise.then(resolve => console.log(resolve))
    baz()
}

foo()
console.log('before bar')

The result:

foo
baz
before bar
should be right after baz, before bar
bar

According to what's written in https://nodejs.dev/ , promise resolve will happen right after the function.

Promises that resolve before the current function ends will be executed right after the current function.

So I expect 'should be right after baz, before bar' to happen right after the end of foo(), before console.log('before bar').
Can someone explain why it doesn't?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

甜`诱少女 2025-02-06 11:47:15

在任务队列中添加了传递给 settimeout 的回调,而与承诺履行或拒绝相关的回调是在微任务队列中添加的。

这些队列仅在您撰写的JavaScript代码的同步执行后才处理

结果,在调用任何异步回调之前,请在bar'之前记录

您的代码如何执行?

  1. 脚本执行开始。

  2. 函数 bar baz foo 已定义。也称为Promise构造函数,它导致 Resolve 函数的调用,同步解决承诺

  3. foo function解决promise 函数称为

    1. 'foo'已在控制台上记录
    2. settimeout 被调用,调度<代码> bar 要异步调用。 bar 将在任务队列
    3. 中添加

    4. 然后,方法在 myPromise 上调用,安排履行处理程序以异步调用。此履行处理程序是在微型任务队列中添加的
    5. baz 函数被调用,记录'baz'在控制台上
  4. foo 函数函数结束。控件返回到下一行 foo 被调用

  5. last console.log 语句,记录'bar bar'控制台

  6. 脚本执行结束

    上登录'bar'

此时结束,控制台输出如下所示:

foo
baz
before bar

任务队列包含执行 bar 函数的任务 mypromise

脚本执行结束后,可以处理任务和微任务队列。

处理微任务队列:

  • 只要呼叫堆栈为空(这是nodejs.dev所指的内容)))
  • 在每个任务

脚本执行是一个任务,并且执行后,MicroTask队列将是第一个要处理的'在控制台上。

最后,处理任务队列, baz 函数被调用,在控制台上记录'baz'


以下可能是一本有用的阅读,以了解微任务和任务队列:

Callbacks passed to setTimeout are added in the task queue whereas the callbacks related to promise fulfilment or rejection are added in the micro-task queue.

These queues are only processed after the synchronous execution of your script, i.e. the javascript code you wrote.

As a result, 'before bar' is logged before any asynchronous callbacks are invoked.

How your code executes?

  1. Script execution starts.

  2. Function bar, baz, and foo are defined. Promise constructor is also called which leads to the invocation of resolve function, resolving the promise synchronously

  3. foo function is called

    1. 'foo' is logged on the console
    2. setTimeout is called, scheduling bar to be called asynchronously. bar will be added in the task queue
    3. then method is called on myPromise, scheduling the fulfilment handler to be invoked asynchronously. This fulfilment handler is added in the micro-task queue
    4. baz function is called, logging 'baz' on the console
  4. foo function ends. Control return to the next line from where foo was called

  5. Last console.log statement is executed, logging 'before bar' on the console

  6. Script execution ends

At this point, console output is as shown below:

foo
baz
before bar

and the task queue contains a task to execute the bar function whereas the micro-task queue contans a micro-task to execute the fulfilment handler of the myPromise.

After the script execution ends, task and micro-task queues can be processed.

The micro-task queue is processed:

  • after each callback as long as the call-stack is empty (this is what nodejs.dev is referring to)
  • after each task

Script execution is a task and after its execution, micro-task queue will be the first one to be processed, logging 'should be right after baz, before bar' on the console.

At last, the task queue is processed, baz function is called, logging 'baz' on the console.


Following might be a helpful read to understand the micro-task and the task queue: JavaScript async callbacks - Promise and setTimeout

热血少△年 2025-02-06 11:47:15

一旦实现或拒绝了承诺,各自的处理程序函数(fullfled或on Repented)将被称为 异步 (在当前线程循环中计划)。

您可能会在下面找到摘要的片段:

Promise.resolve("I resolved").then((v) => console.log(v));
console.log("hello");

The MDN documentation for Promise.prototype.then states (emphasis is mine):

Once a Promise is fulfilled or rejected, the respective handler function (onFulfilled or onRejected) will be called asynchronously (scheduled in the current thread loop).

You might find the snippet below enlightening:

Promise.resolve("I resolved").then((v) => console.log(v));
console.log("hello");

温柔戏命师 2025-02-06 11:47:15

如果想了解异步概念,则应查看此很棒的

在此处运行的顺序

我将尝试向您解释代码如何首先 ,我们正在用功能初始化所有变量。
然后,我们正在调用 foo(),然后 console.log('baz')。

调用 foo foo 将输入 stack 。和 foo 已登录到控制台。

然后 settimeout(bar,0)被调用。 settimeout(bar,0)异步,将在稍后调用,并将其推入回调队列(当堆栈为空时,稍后将调用)。这就是为什么我们没有看到 bar 的控制台。

在此 mypromise.then(resolve =&gt; console.log(resolve))被调用之后。这也是异步调用。因此,这也将被推到回调队列。

然后将执行 baz()。这就是为什么我们在 foo 之后看到 baz 的日志的原因。

现在记住,我们在堆栈中 console.log('ther bar'),因此将首先记录下来。之后,将调用所有回调队列中的所有项目。

到目前为止已记录三件事: -
foo
BAZ
现在在bar

现在,关于承诺的好处是,他们在回调队列中被优先考虑。因此,即使 settimeout 在我们的承诺之前被调用,如果承诺是执行,它将是优先级

这就是为什么'应该在BAZ之后立即进行的原因,然后在BAR'之前调用 bar

If want to understand the asynchronous concept, you should check out this awesome video.

I'll try to explain to you the sequence of how the code is running here

First of all, we are Initializing all the variables with functions.
Then we're calling foo(), and later console.log('before baz').

What will happen on calling foo is foo will enter the stack. And foo is logged into the console.

Then setTimeout(bar, 0) is being called. setTimeout(bar, 0) being asynchronous, will be called later and pushed in the callback queue(this will be called later when the stack is empty). That's why we didn't see the console of bar.

After this myPromise.then(resolve => console.log(resolve)) is called. And this is also an asynchronous call. So this will also be pushed to the callback queue.

Then baz() will be executed. And that's why we're seeing a log of baz after the foo.

Now remember, we've console.log('before bar') in the stack, so this will be logged first. And after this all the items in the callback queue will be called.

Three things are logged up to now:-
foo
baz
before bar

Now, the good thing about promises is they are being prioritized in the callback queue, over anything. So even setTimeout is being called before the our promise, if promise is executed, it will be prioritized.

That's the reason why 'should be right after baz, before bar' is called before bar.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文