3

概括

我正在查看带有 shadow DOM 和 customElements 的 TODO MVC 示例,litRender.js中,函数中有一个奇怪的代码invalidate():'await 0'。我想知道这段代码的目的是什么。

背景

我在谷歌上做了一些搜索,但我找不到任何这样的案例。我对 javascript 和 Webpack 非常陌生,所以我不知道如何调试应用程序(我尝试使用 --devtool 选项重新捆绑它,但出现错误)。

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

litRender.js可以在下面找到src/libs并帮助呈现此应用程序的每个组件。每个组件都litRender使用class SomeComponent extends LitRender (HTMLElement). 如果内容被多次更新,则时间码旨在通过不每次都渲染来帮助提高性能,它会收集渲染时间。在扩展它的组件上调用 this.invalidate 将保留对组件中定义的渲染函数的调用。

正如作者上面提到的,invalidate()是用来渲染shadow DOM的。以下是作者如何使用它

主要问题

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

4

2 回答 2

1

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

希望它可以帮助你理解。

于 2018-12-22T13:55:04.400 回答
1

一年后我终于找到了答案: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是如何处理代码执行的。它有一个称为堆栈的存储,用于跟踪当前函数执行的来源。

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

a()
console.log('end')

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

    a
(Main) -> code outside every brackets

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

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

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

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

于 2020-05-01T03:28:03.253 回答