我有下面的代码,它并没有像我期望的那样工作.

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

根据https://nodejs.dev/ 中所述,promise 解决将在函数之后立即发生.

在当前函数结束之前解析的promise 将在当前函数之后立即执行.

所以我预计"应该在baz之后,在bar之前"会发生在foo()年之后,console.log('before bar')年之前.

推荐答案

传递给setTimeout的回调被添加到任务队列中,而与promise 履行或拒绝相关的回调被添加到微任务队列中.

这些队列仅在after次同步执行脚本(即编写的javascript代码)时处理.

因此,记录'before bar' before调用任何异步回调.

您的代码是如何执行的?

  1. 脚本执行开始.

  2. 定义了功能barbazfoo.还将调用Promise构造函数,从而调用resolve函数,同步解析Promise

  3. 调用foo函数

    1. 控制台上记录了'foo'
    2. 调用setTimeout,调度bar以异步调用.bar将添加到任务队列中
    3. myPromise上调用then方法,将实现处理程序安排为异步调用.此完成处理程序添加到微任务队列中
    4. 调用baz函数,在控制台上记录'baz'
  4. foo功能结束.控件返回到调用foo的下一行

  5. 执行最后console.log条语句,在控制台上记录'before bar'

  6. 脚本执行结束

此时,控制台输出如下:

foo
baz
before bar

任务队列包含执行bar函数的任务,而微任务队列包含执行myPromise的实现处理程序的微任务.

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

已处理微任务队列:

  • 每次回调后,只要调用堆栈为空(this is what nodejs.dev is referring to)
  • 每个任务完成后

脚本执行是一个任务,执行后,微任务队列将是第一个要处理的队列,在控制台上记录'should be right after baz, before bar'.

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


下面的阅读可能有助于理解微任务和任务队列:JavaScript async callbacks - Promise and setTimeout

Javascript相关问答推荐

Angular 拦截器错误处理删除方法问题

添加/删除时React图像上传重新渲染上传的图像

禁用从vue.js 2中的循环创建的表的最后td的按钮

每次子路由重定向都会调用父加载器函数

从实时数据库(Firebase)上的子类别读取数据

被CSS优先级所迷惑

按下同意按钮与 puppeteer 师

我应该绑定不影响状态的函数吗?'

将自定义排序应用于角形数字数组

Promise Chain中的第二个useState不更新

数字时钟在JavaScript中不动态更新

如何通过使用vanilla JS限制字体大小增加或减少两次来改变字体大小

如何在Svelte中从一个codec函数中调用error()?

映射类型定义,其中值对应于键

JavaScript不重定向配置的PATH

面对代码中的错误作为前端与后端的集成

如何在HTMX提示符中设置默认值?

为什么在函数中添加粒子的速率大于删除粒子的速率?

使每个<;li>;元素的 colored颜色 与随机生成的 colored颜色 列表不同(不重复

FileReader()不能处理Firefox和GiB文件