【问题标题】:Executing priority of fetch() and setTimeout() in ChromeChrome 中 fetch() 和 setTimeout() 的执行优先级
【发布时间】:2020-05-19 20:14:16
【问题描述】:

根据我对事件循环的理解,以下代码将首先输出“Sync 2”,然后是“Sync 4”(同步代码),然后是“Promise 3”(fetch 返回一个 Promise,该 Promise 将被放入微任务队列和将在同步代码完成并且数据从 API 返回后执行),最后是“异步 1”(setTimeout 将被放置在优先级最低的宏任务/回调队列中)。

但是,在最新版本的 Chrome 中,如果我将 setTimeout() 设置为 0,如下所示,我总是在“Promise 3”之前得到“Async 1”。我有什么误解吗?是否有可能一个尚未解决的 Promise 的优先级低于此处的宏任务队列中的某些内容?

setTimeout(() => console.log('Async 1'), 0);

console.log('Sync 2')

fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits').then(() => console.log('Promise 3'))

console.log('Sync 4')

【问题讨论】:

  • 顺序取决于获取实际需要多长时间 - settimeout 为 0 不会等待获取完成 - 微任务(承诺)队列处理 Promise,而不是网络请求

标签: javascript asynchronous promise fetch settimeout


【解决方案1】:

您的fetch 调用必须至少进入浏览器缓存并可能进入网络(以重新验证缓存中的某些内容),因此您根本无法对调用履行处理程序的时间做出任何假设除此之外它不会是同步的。履行处理程序调用可能会立即排队(尽管我倾向于怀疑它),在这种情况下它会在下一个任务(setTimeout 回调)之前运行,但更有可能它至少会被暂时搁置。从根本上说,这取决于浏览器中fetch 的实现,它依赖于实现,与任务或微任务无关。

【讨论】:

  • 它是否与“尚未解决的承诺”有关,即使在微任务队列中,其优先级也会低于任务队列中的其他人?或者只是 fetch 的实现决定了这里的顺序,即它是在 setTimeout 之前还是之后将 promise 排队?
  • @JohnnyHuynh - 待处理的承诺(尚未确定的承诺)根本不在微任务队列中。在承诺得到解决(履行或拒绝)之前,这种情况不会发生。这是进入微任务队列的履行/拒绝回调。所以你排队你的任务(setTimeout),开始你的fetch,并且(显然)fetch 没有兑现 X 时间的承诺。同时,有一个事件循环,所以你的setTimeout 回调被调用。在某些时候,fetch 机制实现了承诺,它将微任务排队,在微任务下一次运行时运行。
【解决方案2】:

(fetch 返回一个 Promise,它会被放入微任务队列中,并在同步代码完成并从 API 返回数据后执行)

仅当返回的 Promise 立即解决时才适用 - 例如,Promise.resolve。如果fetch 返回的 Promise 立即解决,那么您是对的,Promise 3 将在setTimeout 之前记录。

但是fetch 确实不会立即解决 - 它需要端点首先响应,这需要一些时间,因此您首先会看到setTimeout 日志。

【讨论】:

  • 所以一个尚未解决的承诺将首先在微任务队列中排队,但在它解决之前不会优先于任务队列中的其他事物,或者这样的承诺甚至不会去如果还没有解决队列呢?
  • .then 回调仅在 Promise 解决时进入微任务队列。由于 Promise 还没有解决,所以还没有进入任何队列; setTimeout 回调首先运行。然后,几毫秒后,当请求完成时,fetch Promise 解析,然后进入微任务队列。
  • @CertainPerformance - 只是一点点:这个词是“解决”,而不是“解决”。解决一个 Promise 并不一定解决它(你可以将它解决为另一个 Promise)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-11
  • 1970-01-01
  • 1970-01-01
  • 2016-08-28
  • 1970-01-01
  • 2016-04-16
相关资源
最近更新 更多