diff --git a/1-js/05-data-types/01-primitives-methods/article.md b/1-js/05-data-types/01-primitives-methods/article.md index 00f75b3aaf..c2073a66a0 100644 --- a/1-js/05-data-types/01-primitives-methods/article.md +++ b/1-js/05-data-types/01-primitives-methods/article.md @@ -68,7 +68,7 @@ alert( str.toUpperCase() ); // HELLO 所以原始类型可以提供方法,但它们依然是轻量级的。 -JavaScript 引擎高度优化了这个过程。它甚至可能跳过创建额外的对象。但是它仍然必须遵守规范,并且表现得好像它创造了一样。 +JavaScript 引擎高度优化了这个过程。它甚至可能跳过创建额外的对象。但是它仍然必须遵守规范,并且表现得好像它创建了一样。 数字有其自己的方法,例如,[toFixed(n)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed) 将数字四舍五入到给定的精度: diff --git a/1-js/10-error-handling/2-custom-errors/article.md b/1-js/10-error-handling/2-custom-errors/article.md index 2385998d28..4b72741a03 100644 --- a/1-js/10-error-handling/2-custom-errors/article.md +++ b/1-js/10-error-handling/2-custom-errors/article.md @@ -119,7 +119,7 @@ try { // ... ``` -使用 `instanceof` 的版本要好得多,因为将来我们会对 `ValidationError` 进行扩展,创造它的子类型,例如 `PropertyRequiredError`。而 `instanceof` 检查对于新的继承类也适用。所以这是面向未来的做法。 +使用 `instanceof` 的版本要好得多,因为将来我们会对 `ValidationError` 进行扩展,创建它的子类型,例如 `PropertyRequiredError`。而 `instanceof` 检查对于新的继承类也适用。所以这是面向未来的做法。 还有一点很重要,在 `catch` 遇到了未知的错误,它会在 `(**)` 行将该错误再次抛出。`catch` 块只知道如何处理 validation 错误和语法错误,而其他错误(由于代码中的错字或其他未知的错误)应该被扔出(fall through)。 diff --git a/2-ui/99-ui-misc/03-event-loop/article.md b/2-ui/99-ui-misc/03-event-loop/article.md index 31e021fd2f..dae3c99033 100644 --- a/2-ui/99-ui-misc/03-event-loop/article.md +++ b/2-ui/99-ui-misc/03-event-loop/article.md @@ -1,64 +1,64 @@ # 事件循环:微任务和宏任务 -JavaScript 在浏览器里的执行流程跟在 Node.js 中一样,是基于**事件循环**的。 +浏览器中 JavaScript 的执行流程和 Node.js 中的流程都是基于 **事件循环** 的。 -理解事件循环如何运行对于代码优化是重要的,有时对于正确的架构也很重要。 +理解事件循环的工作方式对于代码优化很重要,有时对于正确的架构也很重要。 -在本章中我们首先覆盖关于这个事情是如何运作的理论细节,然后看看这个知识的实际应用。 +在本章中,我们首先介绍有关事物工作方式的理论细节,然后介绍该知识的实际应用。 ## 事件循环 -**事件循环**的概念非常简单。它是一个在 JavaScript 引擎等待任务、执行任务和休眠等待更多任务这几个状态之间的无穷无尽的循环。 +**事件循环** 的概念非常简单。它是一个在 JavaScript 引擎等待任务,执行任务和进入休眠状态等待更多任务这几个状态之间转换的无限循环。 -执行引擎通用的算法: +引擎的一般算法: 1. 当有任务时: - - 从最先进入的任务开始执行 -2. 休眠到有新的任务进入,然后到第 1 步 + - 从最先进入的任务开始执行。 +2. 休眠直到出现任务,然后转到第 1 步。 -当我们浏览一个网页时就是上述这种形式。JavaScript 引擎大多数时候什么也不做,只在一个脚本、处理函数或者事件被激活时运行。 +当我们浏览一个网页时就是上述这种形式。JavaScript 引擎大多数时候不执行任何操作,仅在脚本/处理程序/事件激活时执行。 -任务举例: +任务示例: -- 当外部脚本 ` - ``` -……但是我们可能会想要在执行任务期间展示一些东西,例如进度条。 +……但是我们也可能想在任务执行期间展示一些东西,例如进度条。 -如果我们用 `setTimeout` 拆分繁重任务为小片段,值的改变就会在它们之间被绘制。 +如果我们使用 `setTimeout` 将繁重的任务拆分成几部分,那么变化就会被在它们之间绘制出来。 -这样看起来好多了: +这看起来更好看: ```html run
@@ -200,7 +197,7 @@ count(); function count() { - // 执行一些繁重的工作 (*) + // 做繁重的任务的一部分 (*) do { i++; progress.innerHTML = i; @@ -214,41 +211,42 @@ count(); count(); -``` +``` + +现在 `div` 显示了 `i` 的值的增长,这就是进度条的一种。 -现在 `div` 展示了 `i` 的值的增长,跟进度条很类似了。 ## 用例 3:在事件之后做一些事情 -在事件处理中我们可能要延期一些行为的执行,直到事件冒泡完成并被所有层级接手和处理之后。我们可以把这部分代码放在 0 延迟的 `setTimeout`。 +在事件处理程序中,我们可能会决定推迟某些行为,直到事件冒泡并在所有级别上得到处理后。我们可以通过将该代码包装到零延迟的 `setTimeout` 中来做到这一点。 -在[生成自定义事件](https://zh.javascript.info/dispatch-events)章节中,我们看到这样一个例子:自定义事件 `menu-open` 在 `setTimeout` 中被派发,所以它发生在“click”事件被完全处理后。 +在 一章中,我们看到过这样一个例子:自定义事件 `menu-open` 被在 `setTimeout` 中分派(dispatched),所以它在 `click` 事件被处理完成之后发生。 ```js menu.onclick = function() { // ... - // 创建一个附带被点击菜单项数据的自定义事件 + // 创建一个具有被点击的菜单项的数据的自定义事件 let customEvent = new CustomEvent("menu-open", { bubbles: true }); - // 异步派发自定义事件 + // 异步分派(dispatch)自定义事件 setTimeout(() => menu.dispatchEvent(customEvent)); }; ``` ## 宏任务和微任务 -伴随本章描述的**宏任务**还存在着**微任务**,在章节[微任务](https://zh.javascript.info/microtask-queue)有提及到。 +除了本章中所讲的 **宏任务(macrotask)** 外,还有在 一章中提到的 **微任务(microtask)**。 -微任务仅仅由我们的代码产生。它们通常由 promises 生成:对于 `.then/catch/finally` 的处理函数变成了一个微任务。微任务通常"隐藏在" `await` 下,因为它也是另一种处理 promise 的形式。 +微任务仅来自于我们的代码。它们通常是由 promise 创建的:对 `.then/catch/finally` 处理程序的执行会成为微任务。微任务也被用于 `await` 的“幕后”,因为它是 promise 处理的另一种形式。 -有一个特殊的函数 `queueMicrotask(func)`,可以将 `func` 加入到微任务队列来执行。 +还有一个特殊的函数 `queueMicrotask(func)`,它对 `func` 进行排队,以在微任务队列中执行。 -**在每个宏任务之后,引擎立即执行所有微任务队列中的任务,比任何其他的宏任务或者渲染或者其他事情都要优先。** +**每个宏任务之后,引擎会立即执行微任务队列中的所有任务,然后再执行其他的宏任务,或渲染,或进行其他任何操作。** -来看看例子: +例如,看看下面这个示例: ```js run setTimeout(() => alert("timeout")); @@ -259,23 +257,23 @@ Promise.resolve() alert("code"); ``` -这里的执行顺序是什么呢? +这里的执行顺序是怎样的? -1. `code` 首先出现,因为它是常规的同步调用。 -2. `promise` 第二个出现,因为 `then` 从微任务队列中来,在当前代码之后执行。 -3. `timeout` 最后出现,因为它是一个宏任务。 +1. `code` 首先显示,因为它是常规的同步调用。 +2. `promise` 第二个出现,因为 `then` 会通过微任务队列,并在当前代码之后执行。 +3. `timeout` 最后显示,因为它是一个宏任务。 -更详细的事件循环图如下: +更详细的事件循环图示如下(顺序是从上到下,即:首先是脚本,然后是微任务,渲染等): ![](eventLoop-full.svg) -**所有的微任务在任何其他的事件处理或者渲染或者任何其他的宏任务发生之前完成调用。** +微任务会在执行任何其他事件处理,或渲染,或执行任何其他宏任务之前完成。 -这非常重要,因为它保证了微任务中的程序运行环境基本一致(没有鼠标位置改变,没有新的网络返回数据,等等)。 +这很重要,因为它确保了微任务之间的应用程序环境基本相同(没有鼠标坐标更改,没有新的网络数据等)。 -如果我们想要异步执行(在当前代码之后)一个函数,但是要在修改被渲染或者新的事件被处理之前,我们可以用 `queueMicrotask` 来定时执行。 +如果我们想要异步执行(在当前代码之后)一个函数,但是要在更改被渲染或新事件被处理之前执行,那么我们可以使用 `queueMicrotask` 来对其进行安排(schedule)。 -还是跟前面的类似的“数数型进度展示条”的例子,不同的是用 `queueMicrotask` 来代替 `setTimeout`。你可以看到它在最后才渲染。就像写的是同步代码: +这是一个与前面那个例子类似的,带有“计数进度条”的示例,但是它使用了 `queueMicrotask` 而不是 `setTimeout`。你可以看到它在最后才渲染。就像写的是同步代码一样: ```html run
@@ -285,14 +283,16 @@ alert("code"); function count() { - // 执行一些繁重的工作 (*) + // 做繁重的任务的一部分 (*) do { i++; progress.innerHTML = i; } while (i % 1e3 != 0); if (i < 1e6) { + *!* queueMicrotask(count); + */!* } } @@ -303,37 +303,37 @@ alert("code"); ## 总结 -更具体的事件循环的算法(尽管跟[标准](https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model)相比是简化过的): +事件循环的更详细的算法(尽管与 [规范](https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model) 相比仍然是简化过的): -1. 从**宏任务**队列出列并执行最前面的任务(比如“script”)。 -2. 执行所有的**微任务**: +1. 从 **宏任务** 队列(例如 "script")中出队(dequeue)并执行最早的任务。 +2. 执行所有 **微任务**: - 当微任务队列非空时: - - 出列并运行最前面的微任务。 -3. 如有需要执行渲染。 -4. 如果宏任务队列为空,休眠直到一个宏任务出现。 -5. 到步骤 1 中。 + - 出队(dequeue)并执行最早的微任务。 +3. 执行渲染,如果有。 +4. 如果宏任务队列为空,则休眠直到出现宏任务。 +5. 转到步骤 1。 -计划一个新的**宏任务**: -- 使用 0 延时的 `setTimeout(f)`。 +安排(schedule)一个新的 **宏任务**: +- 使用零延迟的 `setTimeout(f)`。 -它被用来拆分一个计算耗费型任务为小片段,使浏览器可以对用户行为作出反馈和展示计算的进度。 +它可被用于将繁重的计算任务拆分成多个部分,以使浏览器能够对用户事件作出反应,并在任务的各部分之间显示任务进度。 -也被用在事件处理函数中来定时执行一个行为,在当前事件被完全处理(冒泡结束)之后。 +此外,也被用于在事件处理程序中,将一个行为(action)安排(schedule)在事件被完全处理(冒泡完成)后。 -计划一个新的**微任务**: +安排一个新的 **微任务**: - 使用 `queueMicrotask(f)`。 -- promise 的处理函数也是进入到微任务队列。 +- promise 处理程序也会通过微任务队列。 -在微任务中间没有 UI 或者网络事件的处理:它们一个接一个地立即执行。 +在微任务之间没有 UI 或网络事件的处理:它们一个立即接一个地执行。 -所以我们可以用 `queueMicrotask` 来异步地执行函数,但是保持环境状态的一致。 +所以,我们可以使用 `queueMicrotask` 来在保持环境状态一致的情况下,异步地执行一个函数。 ```smart header="Web Workers" -为了繁重任务不至于阻塞事件循环,我们可以用 [Web Workers](https://html.spec.whatwg.org/multipage/workers.html)。 +对于不应该阻塞时间循环的耗时长的繁重计算任务,我们可以使用 [Web Workers](https://html.spec.whatwg.org/multipage/workers.html)。 -这是一个在平行线程中运行代码的办法。 +这是在另一个并行线程中运行代码的方式。 -Web Workers 可以跟主线程交换信息,但是它们可以有自己的变量和自己的事件循环。 +Web Workers 可以与主线程交换消息,但是它们具有自己的变量和事件循环。 -Web Workers 无权访问 DOM,所以它们主要在计算上有用,用来使用多核 CPU 同时执行的能力。 +Web Workers 没有访问 DOM 的权限,因此,它们对于同时使用多个 CPU 内核的计算非常有用。 ``` diff --git a/7-animation/1-bezier-curve/article.md b/7-animation/1-bezier-curve/article.md index b6a68d174a..a0aa5b30f6 100644 --- a/7-animation/1-bezier-curve/article.md +++ b/7-animation/1-bezier-curve/article.md @@ -100,7 +100,7 @@ **德卡斯特里奥算法构造三点贝塞尔曲线:** 1. 绘制控制点。在上面的演示中,它们标有:`1`、`2` 和 `3`。 -2. 创造控制点 1 -> 2 -> 3 间的线段. 在上面的演示中它们是棕色的。 +2. 创建控制点 1 -> 2 -> 3 间的线段. 在上面的演示中它们是棕色的。 3. 参数 `t` 从 `0` to `1` 变化。 在上面的演示中取值 `0.05`:循环遍历 `0, 0.05, 0.1, 0.15, ... 0.95, 1`。 对于每一个 `t` 的取值: diff --git a/8-web-components/1-webcomponents-intro/article.md b/8-web-components/1-webcomponents-intro/article.md index e5a2a990c6..7dcb5a1140 100644 --- a/8-web-components/1-webcomponents-intro/article.md +++ b/8-web-components/1-webcomponents-intro/article.md @@ -26,7 +26,7 @@ ……并且这个家伙能飞,它让人类在太空中能够生存! -这些复杂的设备是如何被创造的? +这些复杂的设备是如何被创建的? 我们可以从中借鉴哪些原则,让我们的开发项目同样的可靠并且可大规模化呢?或者至少让我们可以接近这些目标。 @@ -69,7 +69,7 @@ 而现在浏览器已经原生支持了「Web Components」,我们就可以不用再自己去模拟组件化的结构了。 - [Custom elements](https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements) —— 用于自定义 HTML 元素. -- [Shadow DOM](https://dom.spec.whatwg.org/#shadow-trees) —— 为组件创造内部 DOM,它对外部是不可见的。 +- [Shadow DOM](https://dom.spec.whatwg.org/#shadow-trees) —— 为组件创建内部 DOM,它对外部是不可见的。 - [CSS Scoping](https://drafts.csswg.org/css-scoping/) —— 申明仅应用于组件的 Shadow DOM 内的样式。 - [Event retargeting](https://dom.spec.whatwg.org/#retarget) 以及更多的小东西,让自定义组件更适用于开发工作。