Skip to content

Commit

Permalink
zh-cn: resolve the global functions clearTimeout() & setTimeout()
Browse files Browse the repository at this point in the history
  • Loading branch information
yin1999 committed Oct 8, 2024
1 parent 403d38c commit 452ff40
Show file tree
Hide file tree
Showing 42 changed files with 397 additions and 291 deletions.
1 change: 0 additions & 1 deletion files/zh-cn/_redirects.txt
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,6 @@
/zh-CN/docs/DOM/window.setImmediate /zh-CN/docs/Web/API/Window/setImmediate
/zh-CN/docs/DOM/window.setInterval /zh-CN/docs/Web/API/Window/setInterval
/zh-CN/docs/DOM/window.setTimeout /zh-CN/docs/Web/API/Window/setTimeout
/zh-CN/docs/DOM/window.setTimeout12 /zh-CN/docs/Web/API/Window/setTimeout
/zh-CN/docs/DOM/文件系统API的基本概念 /zh-CN/docs/Web/API/File_and_Directory_Entries_API/Introduction
/zh-CN/docs/DOM:HTMLDocument /zh-CN/docs/Web/API/HTMLDocument
/zh-CN/docs/DOM:XMLDocument /zh-CN/docs/Web/API/XMLDocument
Expand Down
8 changes: 4 additions & 4 deletions files/zh-cn/games/anatomy/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,17 +209,17 @@ var tNow = window.performance.now();

一种常见的技术是以恒定的频率更新模拟,然后绘制尽可能多的(或尽可能少的)实际帧。更新方法可以继续循环,而不用考虑用户看到的内容。绘图方法可以查看最后的更新以及发生的时间。由于绘制知道何时表示,以及上次更新的模拟时间,它可以预测为用户绘制一个合理的框架。这是否比官方更新循环更频繁(甚至更不频繁)无关紧要。更新方法设置检查点,并且像系统允许的那样频繁地,渲染方法画出周围的时间。在 Web 标准中分离更新方法有很多种方法:

-`requestAnimationFrame()` 中绘制,并在 {{domxref("Window.setInterval", "setInterval()")}} 或 {{domxref("setTimeout()")}} 中更新。
-`requestAnimationFrame()` 中绘制,并在 {{domxref("Window.setInterval", "setInterval()")}} 或 {{domxref("Window.setTimeout", "setTimeout()")}} 中更新。

- 即使在未聚焦或最小化的情况下,使用处理器时间,也可能是主线程,并且可能是传统游戏循环的工件(但是很简单)。

- 绘制 `requestAnimationFrame` 并在 [Web Worker](/zh-CN/docs/Web/API/Web_Workers_API/Using_web_workers)`setInterval``setTimeout` 中对其进行更新。
- `requestAnimationFrame()` 中绘制,并在 [Web Worker](/zh-CN/docs/Web/API/Web_Workers_API/Using_web_workers){{domxref("WorkerGlobalScope.setInterval", "setInterval()")}} 或 {{domxref("WorkerGlobalScope.setTimeout", "setTimeout()")}} 中对其进行更新。

- 这与上述相同,除了更新不会使主线程(主线程也没有)。这是一个更复杂的解决方案,并且对于简单更新可能会有太多的开销。

- 绘制 `requestAnimationFrame` 并使用它来戳一个包含更新方法的 Web Worker,其中包含要计算的刻度数(如果有的话)。
- `requestAnimationFrame()` 中绘制,并使用它来戳一个包含更新方法的 Web Worker,其中包含要计算的刻度数(如果有的话)。

- 这个睡眠直到 `requestAnimationFrame` 被调用并且不会污染主线程,加上你不依赖于老式的方法。再次,这比以前的两个选项更复杂一些,并且*开始*每个更新将被阻止,直到浏览器决定启动 rAF 回调。
- 这个睡眠直到 `requestAnimationFrame()` 被调用并且不会污染主线程,加上你不依赖于老式的方法。再次,这比以前的两个选项更复杂一些,并且*开始*每个更新将被阻止,直到浏览器决定启动 rAF 回调。

这些方法中的每一种都有类似的权衡:

Expand Down
2 changes: 1 addition & 1 deletion files/zh-cn/glossary/callback_function/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ console.log(value);

如果 `doSomething` 同步调用回调,则最后一条语句将记录 `2`,因为 `value = 2` 是同步执行的;如果回调是异步的,最后一条语句将记录 `1`,因为 `value = 2` 将在 `console.log` 语句之后执行。

同步回调的示例包括传递给 {{jsxref("Array.prototype.map()")}}、{{jsxref("Array.prototype.forEach()")}} 等的回调。异步回调的示例包括传递给 [`setTimeout()`](/zh-CN/docs/Web/API/setTimeout) 和 {{jsxref("Promise.prototype.then()")}} 的回调。
同步回调的示例包括传递给 {{jsxref("Array.prototype.map()")}}、{{jsxref("Array.prototype.forEach()")}} 等的回调。异步回调的示例包括传递给 {{domxref("Window.setTimeout", "setTimeout()")}} 和 {{jsxref("Promise.prototype.then()")}} 的回调。

[使用 Promise](/zh-CN/docs/Web/JavaScript/Guide/Using_promises#时序) 指南提供了有关异步回调时序的更多信息。

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ slug: Learn/JavaScript/Asynchronous/Implementing_a_promise-based_API

### 用 setTimeout() 包裹

我们将会使用 {{domxref("setTimeout()")}} 来实现 `alarm()` 函数。`setTimeout()` 以一个回调函数和一个以毫秒为单位的延迟作为参数。当调用 `setTimeout()` 时,它将启动一个设置为给定延迟的计时器,当时间过期时,它就会调用给定的回调函数。
我们将会使用 {{domxref("Window.setTimeout", "setTimeout()")}} 来实现 `alarm()` 函数。`setTimeout()` 以一个回调函数和一个以毫秒为单位的延迟作为参数。当调用 `setTimeout()` 时,它将启动一个设置为给定延迟的计时器,当时间过期时,它就会调用给定的回调函数。

在下面的例子中,我们使用一个回调函数和一个 1000 毫秒的延迟调用 `setTimeout()`

Expand Down Expand Up @@ -205,7 +205,7 @@ button.addEventListener("click", async () => {

## 参见

- [Promise() 构造器](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise)
- [使用 Promises](/zh-CN/docs/Web/JavaScript/Guide/Using_promises)
- [`Promise()` 构造函数](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise)
- [使用 promise](/zh-CN/docs/Web/JavaScript/Guide/Using_promises)

{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Promises", "Learn/JavaScript/Asynchronous/Introducing_workers", "Learn/JavaScript/Asynchronous")}}
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ const checkAllTodos = (completed) => {

在这种情况下,当 `editing``false` 时,编辑 `<input>` 不可见,因为它不存在于 DOM 中。在 `onEdit()` 函数中,我们将 `editing` 设置为 `true`,然后立即尝试访问 `nameEl` 变量并执行 `nameEl.focus()`。问题在于,Svelte 还没有更新 DOM。

解决这个问题的一种方法是使用 [`setTimeout()`](/zh-CN/docs/Web/API/setTimeout) 函数,延迟调用 `nameEl.focus()`,直到下一个事件循环,并给 Svelte 更新 DOM 的机会。
解决这个问题的一种方法是使用 {{domxref("Window.setTimeout", "setTimeout()")}} 函数,延迟调用 `nameEl.focus()`,直到下一个事件循环,并给 Svelte 更新 DOM 的机会。

现在尝试一下这个解决方案:

Expand Down
4 changes: 2 additions & 2 deletions files/zh-cn/mozilla/add-ons/webextensions/api/alarms/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
title: alarms
slug: Mozilla/Add-ons/WebExtensions/API/alarms
l10n:
sourceCommit: b795bc99fc5c5d8a96c1b202a12750404085c28a
sourceCommit: 1b4e6d1156e8471d38deeea1567c35ef412c5f42
---

{{AddonSidebar}}

在未来一个特定的时间运行的计划任务代码。这很像 [`setTimeout()`](/zh-CN/docs/Web/API/WindowTimers/setTimeout){{domxref("Window.setInterval()")}}{{domxref("WorkerGlobalScope.setInterval()")}},不过这些函数仅可以按需使用而不能在后台页面工作。
在未来一个特定的时间运行的计划任务代码。这很像 {{domxref("Window.setTimeout()")}}{{domxref("Window.setInterval()")}},不过这些函数仅可以按需使用而不能在后台页面工作。

闹钟不会在浏览器会话之间持续存在。它们在单个扩展的所有上下文中全局创建。例如,在后台脚本中创建的闹钟将在后台脚本、选项页面、弹出页面和扩展标签页中触发 [`onAlarm`](/zh-CN/docs/Mozilla/Add-ons/WebExtensions/API/alarms/onAlarm) 事件(反之亦然)。闹钟 API 在[内容脚本](/zh-CN/docs/Mozilla/Add-ons/WebExtensions/Content_scripts#webextension_apis)中不可用。

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ In page script, window.x: 1
In page script, window.y: undefined
```
上述内容同样适用于 [`setTimeout()`](/zh-CN/docs/Web/API/setTimeout)、{{domxref("Window.setInterval", "setInterval()")}} 和 [`Function()`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function)。
上述内容同样适用于 {{domxref("Window.setTimeout", "setTimeout()")}}、{{domxref("Window.setInterval", "setInterval()")}} 和 [`Function()`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function)。
> [!WARNING]
> 在页面的上下文中运行代码时要非常小心!
Expand Down
41 changes: 0 additions & 41 deletions files/zh-cn/web/api/background_tasks_api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,47 +26,6 @@ slug: Web/API/Background_Tasks_API
- **避免运行时间无法预测的任务**。你的空闲回调必须避免做任何占用时间不可预测的事情。比如说,应该避免做任何会影响页面布局的事情。你也必须避免 执行{{domxref("Promise")}} 的 `resolve``reject`,因为这会在你的回调函数返回后立即引用 Promise 对象对 `resolve``reject` 的处理程序。
- **在你需要的时候要用 timeout,但记得只在需要的时候才用**。使用 timeout 可以保证你的代码按时执行,但是在剩余时间不足以强制执行你的代码的同时保证浏览器的性能表现的情况下,timeout 就会造成延迟或者动画不流畅。

### 回退到 setTimeout

因为后台任务 API 还是相当新的,而你的代码可能需要在那些不仍不支持此 API 的浏览器上运行。你可以把 {{domxref("WindowTimers.setTimeout()", "setTimeout()")}} 用作回调选项来做这样的事。这个并不是 {{Glossary("polyfill")}} ,因为它在功能上并不相同;`setTimeout()` 并不会让你利用空闲时段,而是使你的代码在情况允许时执行你的代码,以使我们可以尽可能地避免造成用户体验性能表现延迟的后果。

```js
window.requestIdleCallback =
window.requestIdleCallback ||
function (handler) {
let startTime = Date.now();

return setTimeout(function () {
handler({
didTimeout: false,
timeRemaining: function () {
return Math.max(0, 50.0 - (Date.now() - startTime));
},
});
}, 1);
};
```

如果 {{domxref("Window.requestIdleCallback", "window.requestIdleCallback")}} 是 undefined, 我们在这里把它创建出来。这个函数首先会记录我们调用具体实现的时间。我们将用它计算填充程序 {{domxref("IdleDeadline.timeRemaining()", "timeRemaining()")}} 返回的值。

接着,我们调用 {{domxref("WindowTimers.setTimeout", "setTimeout()")}},并给它传一个函数,在这个函数里,我们传给 `requestIdleCallback()` 的具体实现的回调会得以执行。这个回调会接收一个和 {{domxref("IdleDeadline")}} 相符合的 object,此 object 的 {{domxref("IdleDeadline.didTimeout", "didTimeout")}} 被设定为 false,并拥有一个 {{domxref("IdleDeadline.timeRemaining", "timeRemaining()")}} 方法,用来给回调函数 50 毫秒的开始时间。每次调用 `timeRemaining()`,它都会从开始的 50 毫秒中减去已逝去的时间,来确定还剩余的时间。

结果是,虽然我们的填充程序不会像真正的 `requestIdleCallback()` 将自己限制在当前事件循环传递中的空闲时间内,但它至少将每次传递的运行时间限制为不超过 50 毫秒。

我们 {{domxref("Window.cancelIdleCallback", "cancelIdleCallback()")}} 的具体实现要简单的多。

```js
window.cancelIdleCallback =
window.cancelIdleCallback ||
function (id) {
clearTimeout(id);
};
```

如果 `cancelIdleCallback()` 没有定义,它将创建一个来简单地把指定回调 ID 传递给 {{domxref("WindowTimers.clearTimeout", "clearTimeout()")}}。

现在,尽管效率不高,你的代码也可以在不支持后台任务 API 的浏览器上运行了。

## 接口

后台任务 API 只添加了一个新的接口:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ slug: Web/API/Canvas_API/Tutorial/Basic_animations

### 有安排地更新画布

首先,可以用 {{domxref("Window.setInterval", "setInterval()")}}、{{domxref("window.setTimeout()")}} 和 {{domxref("Window.requestAnimationFrame", "requestAnimationFrame()")}} 来设定定期执行一个指定函数。
首先,可以用 {{domxref("Window.setInterval", "setInterval()")}}、{{domxref("Window.setTimeout", "setTimeout()")}} 和 {{domxref("Window.requestAnimationFrame", "requestAnimationFrame()")}} 来设定定期执行一个指定函数。

- {{domxref("Window.setInterval", "setInterval()")}}
- : 当设定好间隔时间后,function 会定期执行。
- {{domxref("setTimeout()")}}
- {{domxref("Window.setTimeout", "setTimeout()")}}
- : 在设定好的时间之后执行函数
- {{domxref("Window.requestAnimationFrame", "requestAnimationFrame()")}}
- : 告诉浏览器你希望执行一个动画,并在重绘之前,请求浏览器执行一个特定的函数来更新动画。
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ if (canvas.getContext) {
</html>
```

上面的脚本中包含一个叫做 draw() 的函数,当页面加载结束的时候就会执行这个函数。通过使用在文档上加载事件来完成。只要页面加载结束,这个函数,或者像是这个的,同样可以使用 {{domxref("WindowTimers.setTimeout", "window.setTimeout()")}}、{{domxref("Window.setInterval", "setInterval()")}},或者其他任何事件处理程序来调用。
上面的脚本中包含一个叫做 draw() 的函数,当页面加载结束的时候就会执行这个函数。通过使用在文档上加载事件来完成。只要页面加载结束,这个函数,或者像是这个的,同样可以使用 {{domxref("Window.setTimeout", "setTimeout()")}}、{{domxref("Window.setInterval", "setInterval()")}},或者其他任何事件处理程序来调用。

模板看起来会是这样。如这里所示,它最初是空白的。

Expand Down
2 changes: 1 addition & 1 deletion files/zh-cn/web/api/document/scroll_event/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ onscroll = (event) => {};

### Scroll 事件限流

由于 `scroll` 事件可被高频触发,事件处理器不应该执行高性能消耗的操作,如 DOM 操作。而更推荐的做法是使用 {{DOMxRef("Window.requestAnimationFrame()", "requestAnimationFrame()")}}、{{DOMxRef("setTimeout()")}} 或 {{DOMxRef("CustomEvent")}} 给事件限流,如下所述。
由于 `scroll` 事件可被高频触发,事件处理器不应该执行高性能消耗的操作,如 DOM 操作。而更推荐的做法是使用 {{DOMxRef("Window.requestAnimationFrame()", "requestAnimationFrame()")}}、{{DOMxRef("Window.setTimeout", "setTimeout()")}} 或 {{DOMxRef("CustomEvent")}} 给事件限流,如下所述。

然而需要注意的是,输入事件和动画帧的触发速度大致相同,因此通常不需要下述优化。此示例使用 `requestAnimationFrame` 优化 `scroll` 事件。

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ JavaScript 本质上是一门单线程语言。对于在它被设计出来的那

当然,随着时间的流逝,计算机已经发展成为强大的多核系统,而 JavaScript 已经成为计算世界中使用最广泛的语言之一。大量最流行的应用程序至少有一部分是基于 JavaScript 代码的。为了支持这一点,有必要找到方法让项目摆脱单线程语言的限制。

自从定时器({{domxref("setTimeout()")}} 和 {{domxref("Window.setInterval", "setInterval()")}})加入到 Web API 后,浏览器提供的 JavaScript 环境就已经逐渐发展到包含任务调度、多线程应用开发等强大的特性。了解 JavaScript 运行时是如何安排和运行代码的对了解 `queueMicrotask()` 会非常有作用。
自从定时器({{domxref("Window.setTimeout", "setTimeout()")}} 和 {{domxref("Window.setInterval", "setInterval()")}})加入到 Web API 后,浏览器提供的 JavaScript 环境就已经逐渐发展到包含任务调度、多线程应用开发等强大的特性。了解 JavaScript 运行时是如何安排和运行代码的对了解 `queueMicrotask()` 会非常有作用。

## JavaScript 执行上下文

Expand Down Expand Up @@ -118,7 +118,7 @@ greetUser("Veronica");

#### 任务 vs 微任务

一个**任务**就是指计划由标准机制来执行的任何 JavaScript,如程序的初始化、事件触发的回调等。除了使用事件,你还可以使用 {{domxref("setTimeout()")}} 或者 {{domxref("Window.setInterval", "setInterval()")}} 来添加任务。
一个**任务**就是指计划由标准机制来执行的任何 JavaScript,如程序的初始化、事件触发的回调等。除了使用事件,你还可以使用 {{domxref("Window.setTimeout", "setTimeout()")}} 或者 {{domxref("Window.setInterval", "setInterval()")}} 来添加任务。

任务队列和微任务队列的区别很简单,但却很重要:

Expand Down
2 changes: 1 addition & 1 deletion files/zh-cn/web/api/html_dom_api/microtask_guide/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ JavaScript 中的 [promise](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/

- 一段新程序或子程序被直接执行时(比如从一个控制台,或在一个 {{HTMLElement("script")}} 元素中运行代码)。
- 触发了一个事件,将其回调函数添加到任务队列时。
- 执行到一个由 {{domxref("setTimeout()")}} 或 {{domxref("Window.setInterval", "setInterval()")}} 创建的 timeout 或 interval,以致相应的回调函数被添加到任务队列时。
- 执行到一个由 {{domxref("Window.setTimeout", "setTimeout()")}} 或 {{domxref("Window.setInterval", "setInterval()")}} 创建的 timeout 或 interval,以致相应的回调函数被添加到任务队列时。

事件循环驱动你的代码按照这些任务排队的顺序,一个接一个地处理它们。在事件循环的单次迭代中,将执行任务队列中最旧的可运行任务。之后,微任务将被执行,直到微任务队列为空,然后浏览器可以选择更新渲染。然后浏览器继续进行事件循环的下一次迭代。

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: 使用 Notifications API
slug: Web/API/Notifications_API/Using_the_Notifications_API
l10n:
sourceCommit: 83ec73ac6fec9cae23c54b729e6481f50a0a45e7
sourceCommit: 1b4e6d1156e8471d38deeea1567c35ef412c5f42
---

{{DefaultAPISidebar("Web Notifications")}}{{securecontext_header}}
Expand Down Expand Up @@ -109,7 +109,7 @@ const notification = new Notification("待办列表", { body: text, icon: img })

## 关闭通知

使用 {{domxref("Notification.close","close()")}} 删除不再与用户相关的通知(例如,对于消息应用程序,用户已经阅读了网页上的通知) ,或者以下歌曲已在音乐应用程序中播放以通知歌曲更改)。大多数现代浏览器会在一段时间(大约四秒)后自动关闭通知,但这不是你通常应该关心的事情,因为它取决于用户和用户代理。删除通知也可能发生在操作系统级别,用户应该对此保持控制。旧版本的 Chrome 不会自动删除通知,因此你可以在 {{domxref("setTimeout()")}} 之后执行此操作,以免从其他浏览器的通知托盘中删除通知。
使用 {{domxref("Notification.close","close()")}} 删除不再与用户相关的通知(例如,对于消息应用程序,用户已经阅读了网页上的通知) ,或者以下歌曲已在音乐应用程序中播放以通知歌曲更改)。大多数现代浏览器会在一段时间(大约四秒)后自动关闭通知,但这不是你通常应该关心的事情,因为它取决于用户和用户代理。删除通知也可能发生在操作系统级别,用户应该对此保持控制。旧版本的 Chrome 不会自动删除通知,因此你可以在 {{domxref("Window.setTimeout", "setTimeout()")}} 之后执行此操作,以免从其他浏览器的通知托盘中删除通知。

```js
const n = new Notification("我的歌");
Expand Down
Loading

0 comments on commit 452ff40

Please sign in to comment.