Promise.resolve().then(() => { console.log('start') return Promise.resolve('end')}).then(res => { console.log(res)})Promise.resolve().then(() => { console.log(1)}).then(() => { console.log(2)}).then(() => { console.log(3)}).then(() => { console.log(4)}).then(() => { console.log(5)}).then(() => { console.log(6)})
这是刚从某网站偶然间看到的一道面试题,问打印输出的顺序。
原来全都是数字,为了方便描述我把两个Promise的打印区分开来了。
分开的顺序很好理解,一定是start end
和 1 2 3 4 5 6
但是把他们放到一起顺序我就有点吃不准,放到不同浏览器和vscode(虽然vscode好像也是用V8跑的)中跑了一下,输出顺序始终是start 1 2 3 end 4 5 6
让我很不理解。start
在1
之前是能理解的,如果是start 1 end 2 3 4 5 6
这样也是可以理解的,但是很奇怪的是end
为什么会在3
、4
之间。
想了一会儿突然想到把第一个Promise中的return删了,直接在.then()
里打印end
也就是下面代码这样会怎么样呢?
Promise.resolve().then(() => { console.log('start') Promise.resolve('end').then(res => { console.log(res) })})
果然这次顺序变成了start 1 end 2 3 4 5 6
。
是否就是因为return消耗的额外的时间导致微任务队列额外又加入了console.log(2)
和console.log(3)
呢?
如果是这样这面试题也太坑了吧,不实际敲一下鬼知道return的时间够几个callback进入微任务队列啊,而且这实际已经和event loop没啥关系了吧,实际面试要是遇到这种出这种题目的公司是不是可以直接拉黑了?
关于这道题目衍生,因为实际应用中很少有这道题中的Promise,一般异步同时进行都是多个网络请求,这个时候微任务队列的顺序就和接口响应时间有关,顺序不固定。但是如果Promise中不涉及网络请求,代码一致且完整执行的情况下是否callback进入微任务队列的顺序与Promise进入微任务队列的顺序一致呢?换言之即下列代码,与任何外部情况无关,只要代码执行完毕输出顺序是否一定是1 6 2 7 3 8 4 9 5 10
呢?
Promise.resolve().then(() => { console.log(1)}).then(() => { console.log(2)}).then(() => { console.log(3)}).then(() => { console.log(4)}).then(() => { console.log(5)})Promise.resolve().then(() => { console.log(6)}).then(() => { console.log(7)}).then(() => { console.log(8)}).then(() => { console.log(9)}).then(() => { console.log(10)})
之前也有过类似的疑问,可以看看这个哈,希望对你有所帮助https://www.zhihu.com/question/453677175/answer/2815817162
首先,我们来解析一下为什么第一道代码的输出顺序是 start 1 2 3 end 4 5 6
。
在 JavaScript 中,Promise 的执行是异步的,但它们的回调函数会被放入微任务队列中。这意味着当 Promise 被解决或拒绝时,其相关的回调函数会被放入微任务队列,并在当前同步任务执行完毕后立即执行。
在你的第一道代码中,有两个 Promise,它们分别有自己的 .then
链。当第一个 Promise 被解决时,它的第一个 .then
回调函数被调用,打印出 'start'
,然后返回一个新的 Promise。这个新的 Promise 会立即被解决,但其 .then
回调函数(打印 'end'
)会被放入微任务队列,等待当前同步任务执行完毕后再执行。
此时,第一个 Promise 的第一个 .then
回调函数执行完毕,JavaScript 引擎继续执行后面的代码。它遇到了第二个 Promise 的 .then
链,并依次执行这些 .then
回调函数,打印出 1 2 3
。
当这些 .then
回调函数执行完毕后,JavaScript 引擎会检查微任务队列,并执行其中的任务。这时,第一个 Promise 返回的那个 Promise 的 .then
回调函数被调用,打印出 'end'
。
最后,第二个 Promise 的剩余 .then
回调函数被执行,打印出 4 5 6
。
关于你的第二个问题,是否 Promise
中的回调进入微任务队列的顺序与 Promise
进入微任务队列的顺序一致,答案是肯定的。在你的第二个代码中,所有的 .then
回调函数都按照它们在代码中出现的顺序被放入微任务队列,并在前面的任务执行完毕后依次执行。因此,输出顺序一定是 1 6 2 7 3 8 4 9 5 10
。
至于你提到的面试题是否“坑”,这取决于面试官的目的。如果面试官是想测试你对 JavaScript 异步行为和微任务队列的理解,那么这样的题目是有一定意义的。但是,如果面试官只是想通过一些看似复杂的问题来刁难应聘者,那么这样的题目确实可能会让人感到困扰。在实际应用中,理解 JavaScript 的异步行为和事件循环是非常重要的,因此这样的题目也有一定的教育意义。
主要内容:1.ThreadLocal是什么有什么特性,2.ThreadLocal底层的数据结构,3.ThreadLocal的Map的初始值加载因子是多少,4.ThreadLocal底层的Hash算法是什么,5.ThreadLocal如何解决hash碰撞,6.ThreadLocal的扩容机制,7.ThreadLocal的get方法的流程,8.ThreadLocal的Key是强还是软引用,9.ThreadLocal的Key可能过期吗,,,,,,,,1.ThreadLocal是什么,有什么特性 Thr
打印2的位置 怎么解释呢
主要内容:1.常见的集合有哪些,2.List 、Set和Map 的区别,3.ArrayList,4.ArrayList的扩容机制,5.怎么在遍历 ArrayList 时移除一个元素,6.Arraylist 和 Vector 的区别,7.Arraylist 与 LinkedList 区别,8.HashMap,9.HashMap扩容过程,10.红黑树的特点,11.为什么使用红黑树而不使用AVL树,12.在解决 hash 冲突的时候,为什么选择先用链表,再转红黑树,,,,,,,,,,,,,,,1.常见
请问如何让ar1这种ip排序,js可以实现吗? 另外,我希望是用换行符分割(现在是,分割),排序后也是一行一个。请问可以实现吗
html 代码如上, 我的打印纸张宽度是 176mm, 但是因为我设置了 child2 left:500mm 导致我的纸张被缩放了 理想情况 用 js 的话 我需要判断内部的内容 是否溢出,然后再设置 display:none 如何用 css 去从根节点解决这种问题?
这应该是多线程上的一个简单问题:https://leetcode.com/problems/print-in-order/“同一个Foo实例将传递给三个不同的线程。线程A将调用first(),线程B将调用second(),线程C将调用third()。设计一种机制并修改程序,以确保second()在first()之后执行,third()在second()之后执行”,他们给出以下代码: **看来我可以