当前位置: 首页 > 知识库问答 >
问题:

javascript - 一道js打印输出顺序面试题的相关问题?

牛兴安
2024-04-24
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 end1 2 3 4 5 6
但是把他们放到一起顺序我就有点吃不准,放到不同浏览器和vscode(虽然vscode好像也是用V8跑的)中跑了一下,输出顺序始终是start 1 2 3 end 4 5 6
让我很不理解。start1之前是能理解的,如果是start 1 end 2 3 4 5 6这样也是可以理解的,但是很奇怪的是end为什么会在34之间。
想了一会儿突然想到把第一个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)})

共有2个答案

董砚
2024-04-24

之前也有过类似的疑问,可以看看这个哈,希望对你有所帮助https://www.zhihu.com/question/453677175/answer/2815817162

公良鸿畅
2024-04-24

首先,我们来解析一下为什么第一道代码的输出顺序是 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()之后执行”,他们给出以下代码: **看来我可以