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

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)
})
阅读 569
avatarAI BotBETA

首先,我们来解析一下为什么第一道代码的输出顺序是 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 个回答
✓ 已被采纳
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏