'await 0'有什么用?

What's the usage of 'await 0'?

总结

我正在查看 TODO MVC Example with shadow DOM and customElements and in litRender.js invalidate() 函数中有一个奇怪的代码:'await 0'。我想知道这段代码的用途是什么。

背景

我在 Google 上做了一点搜索,但我找不到任何类似的案例。我是 javascript 和 Webpack 的新手,所以我不知道如何调试应用程序(我尝试使用 --devtool 选项重新捆绑它,但出现错误)。

作者的解释是(抱歉翻译):

litRender.js can be found under src/libs and helps render each component of this application. Each component uses a mix of litRender in the form of class SomeComponent extends LitRender (HTMLElement). If the content is updated several times a time code is intended to help improve performance by not rendering every time, it collected the rendering time. Calling this.invalidate on a component that extends it will reserve a call to the render function defined in the component.

正如作者上面提到的,invalidate()用于渲染阴影DOM。 Here's how the author uses it.

主要问题

我想知道 litRender.js 中 'await 0' 的真正作用。

awaitstatament 必须在 async 代码中使用,以便文档在描述部分中说 hereawait 将用于暂停执行函数直到承诺被解决或拒绝,所以如果 await 旁边的语句不是承诺,那么 JS 将认为是已解决的承诺。

希望能帮助您理解。

一年后我终于找到了答案:await 0 用于 释放事件循环以便浏览器可以绘制框架

注意:我的解释很冗长,并且有一些糟糕的语法用法。阅读上面链接的 MDN 文档可能会更好。

由于 JS 被设计为单线程(同时存在 web worker)语言,因此它具有称为 事件循环 的并发模型。考虑以下情况:

console.log('before timeout')
setTimeout(() => console.log('inside timeout'), 0)
console.log('after timeout')

结果将是:

before timeout
after timeout
inside timeout

一开始可能会让人感到困惑。你可能会想:超时设置为延迟0,因此它会在执行下一行代码之前执行其回调!但事实并非如此。

要理解上面的代码,我们先来看看JS是如何处理代码执行的。它有一个名为 stack 的存储,用于跟踪当前函数执行的来源。

function a() {
  console.log('a()')
}

a()
console.log('end')

上述代码中,括号外的代码先执行。然后,函数a将被执行。此时,堆栈将如下所示:

    a
(Main) -> code outside every brackets

如果某个函数调用另一个函数,被调用的函数将堆叠在前一个函数之上。现在 end 函数和 JS 从栈顶清除它,返回到之前的位置,执行剩余的代码直到到达末尾,等等。通过利用堆栈,JS 可以确定当前函数结束后去哪里。

那我们执行setTimeout会发生什么?这里重要的是 setTimeout 不是语言特性,而是浏览器处理的平台特性。浏览器等待给定时间,同时继续执行代码。然后超时结束,浏览器需要执行它的回调,但问题是另一段代码可能仍在执行。为了解决这个问题,浏览器将回调作为一个任务,并将其注册到任务队列中。其中的任务会在栈为空时依次执行。

这解释了第一个代码片段的奇怪行为:setTimeout 的回调被注册为任务并等待直到堆栈为空。记录第二条消息后,主代码执行结束,回调最终得到执行。

Promise 的处理方式类似(但与 microtask 相同)。无论 await 的右边是否是一个 promise,await 之后需要执行的所有代码都会被注册为 microtask。这样做的主要好处与浏览器仅在堆栈为空时才绘制框架这一事实有关。通过在微任务执行之前在微任务堆栈变空时注册剩余代码,因此浏览器可以在该时间绘制帧。