偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

JavaScript怎么模擬 delay、sleep、pause、wait 方法

開(kāi)發(fā) 前端
盡管在許多其他語(yǔ)言中都有 sleep 函數(shù),但我鼓勵(lì)你去接受JavaScript的異步特性,盡量不要與這門語(yǔ)言作對(duì)。當(dāng)你習(xí)慣了它,它實(shí)際上是相當(dāng)不錯(cuò)的。

許多編程語(yǔ)言都有一個(gè) sleep 函數(shù),可以延遲程序的執(zhí)行若干秒。JavaScript缺少這個(gè)內(nèi)置功能,但不用擔(dān)心。在這篇文章中,我們將探討在JavaScript代碼中實(shí)現(xiàn)延遲的各種技巧,同時(shí)考慮到該語(yǔ)言的異步性質(zhì)。

如何在 JS 中創(chuàng)建 sleep 函數(shù)

對(duì)于那些只想快速解決問(wèn)題而不想深入了解技術(shù)細(xì)節(jié)的人,我們也有簡(jiǎn)單明了的解決方案。下面是如何在你的JavaScript工具箱中添加一個(gè) sleep 函數(shù)的最直接方式:

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

console.log('Hello');
sleep(2000).then(() => { console.log('World!'); });

運(yùn)行這段代碼,你會(huì)在控制臺(tái)看到 “Hello”。然后,在短暫的兩秒鐘后,“World!”v會(huì)接著出現(xiàn)。這是一種既簡(jiǎn)潔又有效的引入延遲的方法。

如果你只是為了這個(gè)來(lái)的,那太好了!但如果你對(duì)“為什么”和“怎么做”的原因感到好奇,還有更多可以學(xué)習(xí)的內(nèi)容。JavaScript中處理時(shí)間有其細(xì)微之處,了解這些可能會(huì)對(duì)你有所幫助。

理解JavaScript的執(zhí)行模型

現(xiàn)在我們已經(jīng)有了一個(gè)快速的解決方案,讓我們深入了解JavaScript的執(zhí)行模型的機(jī)制。理解這一點(diǎn)對(duì)于有效地管理代碼中的時(shí)間和異步操作至關(guān)重要。

考慮以下Ruby代碼:

require 'net/http'
require 'json'

url = 'https://api.github.com/users/jameshibbard'
uri = URI(url)
response = JSON.parse(Net::HTTP.get(uri))
puts response['public_repos']
puts 'Hello!'

正如人們所期望的,這段代碼向GitHub API發(fā)送一個(gè)請(qǐng)求以獲取我的用戶數(shù)據(jù)。然后解析響應(yīng),輸出與我的GitHub帳戶關(guān)聯(lián)的公共倉(cāng)庫(kù)的數(shù)量,最后在屏幕上打印“Hello!”。執(zhí)行是從上到下進(jìn)行的。

相比之下,這是相同功能的JavaScript版本:

fetch('https://api.github.com/users/jameshibbard')
  .then(res => res.json())
  .then(json => console.log(json.public_repos));
console.log('Hello!');

如果你運(yùn)行這段代碼,它會(huì)先在屏幕上輸出“Hello!”,然后輸出與我的GitHub帳戶關(guān)聯(lián)的公共倉(cāng)庫(kù)的數(shù)量。

這是因?yàn)樵贘avaScript中,從API獲取數(shù)據(jù)是一個(gè)異步操作。JavaScript解釋器會(huì)遇到 fetch 命令并發(fā)送請(qǐng)求。然而,它不會(huì)等待請(qǐng)求完成。相反,它會(huì)繼續(xù)執(zhí)行,將“Hello!”輸出到控制臺(tái),然后當(dāng)請(qǐng)求在幾百毫秒后返回時(shí),它會(huì)輸出倉(cāng)庫(kù)的數(shù)量。

如何在JavaScript中正確使用SetTimeout

既然我們已經(jīng)更好地理解了JavaScript的執(zhí)行模型,讓我們看看JavaScript是如何處理延遲和異步代碼的。

在JavaScript中創(chuàng)建延遲的標(biāo)準(zhǔn)方法是使用其 setTimeout 方法。例如:

console.log('Hello');
setTimeout(() => {  console.log('World!'); }, 2000);

這將在控制臺(tái)上輸出 "Hello",然后兩秒后輸出 "World!"。在很多情況下,這已經(jīng)足夠了:做某事,然后在短暫的延遲后,做其他事情。問(wèn)題解決!

但不幸的是,事情并不總是那么簡(jiǎn)單。

你可能會(huì)認(rèn)為 setTimeout 會(huì)暫停整個(gè)程序,但事實(shí)并非如此。它是一個(gè)異步函數(shù),這意味著其余的代碼不會(huì)等待它完成。

例如,假設(shè)你運(yùn)行了以下代碼:

console.log('Hello');
setTimeout(() => { console.log('World!'); }, 2000);
console.log('Goodbye!');

你會(huì)看到以下輸出:

Hello
Goodbye!
World!

注意“Goodbye!”是如何出現(xiàn)在“World!”之前的?這是因?yàn)?nbsp;setTimeout 不會(huì)阻塞其余代碼的執(zhí)行。

這意味著你不能這樣做:

console.log('Hello');
setTimeout(1000);
console.log('World');

"Hello" 和 "World" 會(huì)立即被記錄在控制臺(tái)上,之間沒(méi)有明顯的延遲。

你也不能這樣做:

for (let i = 0; i < 5; i++) {
  setTimeout(() => { console.log(i); }, i * 1000);
}

花一秒鐘考慮一下上面的代碼片段可能會(huì)發(fā)生什么。

它不會(huì)在每個(gè)數(shù)字之間延遲一秒鐘打印數(shù)字 0 到 4。相反,你實(shí)際上會(huì)得到五個(gè) 4,它們?cè)谒拿牒笠淮涡匀看蛴〕鰜?lái)。為什么呢?因?yàn)檠h(huán)不會(huì)暫停執(zhí)行。它不會(huì)等待 setTimeout 完成才進(jìn)入下一次迭代。

那么 setTimeout 實(shí)際上有什么用呢?現(xiàn)在讓我們來(lái)看看。

setTimeout() 函數(shù)的檢查和最佳實(shí)踐

正如你可以在我們的 setTimeout 教程中閱讀到的,原生JavaScript setTimeout 函數(shù)在指定的延遲(以毫秒為單位)后調(diào)用一個(gè)函數(shù)或執(zhí)行一個(gè)代碼片段。

這可能在某些情況下是有用的,例如,如果你希望在訪問(wèn)者瀏覽你的頁(yè)面一段時(shí)間后顯示一個(gè)彈出窗口,或者你希望在從元素上移除懸停效果之前有短暫的延遲(以防用戶意外地鼠標(biāo)移出)。

setTimeout 方法接受一個(gè)函數(shù)的引用作為第一個(gè)參數(shù)。

這可以是函數(shù)的名稱:

function greet(){
  alert('Howdy!');
}
setTimeout(greet, 2000);

它可以是一個(gè)指向函數(shù)的變量(函數(shù)表達(dá)式):

const greet = function(){
  alert('Howdy!');
};
setTimeout(greet, 2000);

或者它可以是一個(gè)匿名函數(shù)(在這種情況下是箭頭函數(shù)):

setTimeout(() => { alert('Howdy!'); }, 2000);

也可以將一段代碼字符串傳遞給 setTimeout 以供其執(zhí)行:

然而,這種方法是不可取的,因?yàn)椋?/p>

  1. 它很難閱讀(因此很難維護(hù)和/或調(diào)試)
  2. 它使用了一個(gè)隱含的 eval,這是一個(gè)潛在的安全風(fēng)險(xiǎn)
  3. 它比替代方案慢,因?yàn)樗仨氄{(diào)用JS解釋器

如前所述,setTimeout 非常適合在延遲后觸發(fā)一次性操作,但也可以使用 setTimeout(或其表親 setInterval)來(lái)讓JavaScript等待直到滿足某個(gè)條件。例如,下面是如何使用 setTimeout 等待某個(gè)元素出現(xiàn)在網(wǎng)頁(yè)上的方式:

function pollDOM () {
  const el = document.querySelector('my-element');

  if (el.length) {
    // Do something with el
  } else {
    setTimeout(pollDOM, 300); // try again in 300 milliseconds
  }
}

pollDOM();

這假設(shè)該元素最終會(huì)出現(xiàn)。如果你不確定這是否會(huì)發(fā)生,你需要考慮取消計(jì)時(shí)器(使用 clearTimeout 或 clearInterval)。

在 JS 中使用遞增超時(shí)作為 Sleep 函數(shù)的替代方案

有時(shí),你可能會(huì)發(fā)現(xiàn)自己想要在一系列操作中引入延遲。雖然你可以使用各種方法來(lái)模擬一個(gè)Sleep函數(shù),但還有另一種經(jīng)常被忽視的方法:遞增超時(shí)。

這個(gè)思路很簡(jiǎn)單:你不是暫停整個(gè)執(zhí)行線程,而是使用 setTimeout 為每個(gè)后續(xù)操作增加延遲。這樣,你可以創(chuàng)建一個(gè)延遲操作的序列,而不會(huì)阻塞瀏覽器或損害用戶體驗(yàn)。

下面是一個(gè)快速示例:

let delay = 1000; // 從1秒的延遲開(kāi)始

for (let i = 0; i < 5; i++) {
  setTimeout(() => {
    console.log(`這是消息 ${i + 1}`);
  }, delay);

  delay += 1000; // 每次迭代延遲增加1秒
}

在這個(gè)示例中,第一條消息將在1秒后出現(xiàn),第二條消息在2秒后,依此類推,直到第五條消息在5秒后。

這種方法的優(yōu)點(diǎn)是它不阻塞,易于實(shí)現(xiàn),并且不需要了解 promises 或 async/await。然而,它不適用于需要精確計(jì)時(shí)或錯(cuò)誤處理的復(fù)雜異步操作

現(xiàn)代JavaScript中的流控制

編寫 JavaScript 時(shí),我們經(jīng)常需要等待某件事情發(fā)生(例如,從 API 獲取數(shù)據(jù)),然后做出響應(yīng)(例如,更新UI以顯示數(shù)據(jù))。

上面的示例使用了一個(gè)匿名回調(diào)函數(shù)來(lái)實(shí)現(xiàn)這一目的,但如果你需要等待多個(gè)事情發(fā)生,語(yǔ)法很快就會(huì)變得相當(dāng)復(fù)雜,你最終會(huì)陷入回調(diào)地獄。

幸運(yùn)的是,這門語(yǔ)言在過(guò)去幾年里有了很大的發(fā)展,現(xiàn)在為我們提供了新的構(gòu)造來(lái)避免這一點(diǎn)。

例如,使用 async await,我們可以重寫最初獲取 GitHub API信息的代碼:

(async () => {
  const res = await fetch(`https://api.github.com/users/jameshibbard`);
  const json = await res.json();
  console.log(json.public_repos);
  console.log('Hello!');
})();

現(xiàn)在,代碼從上到下執(zhí)行。JavaScript 解釋器等待網(wǎng)絡(luò)請(qǐng)求完成,首先記錄公共倉(cāng)庫(kù)的數(shù)量,然后記錄“Hello!”消息。

將Sleep函數(shù)引入原生JavaScript

如果你還在看這篇文章,那么我猜你一定是想阻塞那個(gè)執(zhí)行線程,并讓JavaScript等待一下。

下面是你可能會(huì)這樣做的方式:

function sleep(milliseconds) {
  const date = Date.now();
  let currentDate = null;
  do {
    currentDate = Date.now();
  } while (currentDate - date < milliseconds);
}

console.log('Hello');
sleep(2000);
console.log('World!');

正如預(yù)期的那樣,這將在控制臺(tái)上打印“Hello”,暫停兩秒,然后打印“World!”

它通過(guò)使用Date.now方法獲取自1970年1月1日以來(lái)經(jīng)過(guò)的毫秒數(shù),并將該值分配給一個(gè) date 變量。然后它創(chuàng)建一個(gè)空的 currentDate 變量,然后進(jìn)入一個(gè) do ... while 循環(huán)。在循環(huán)中,它會(huì)重復(fù)獲取自1970年1月1日以來(lái)經(jīng)過(guò)的毫秒數(shù),并將該值分配給之前聲明的 currentDate 變量。只要 date 和 currentDate 之間的差異小于所需的毫秒數(shù)的延遲,循環(huán)就會(huì)繼續(xù)進(jìn)行。

任務(wù)完成了,對(duì)嗎?好吧,也不完全是……

如何在JavaScript中編寫更好的Sleep函數(shù)

也許這段代碼正是你所期望的,但請(qǐng)注意,它有一個(gè)很大的缺點(diǎn):循環(huán)會(huì)阻塞JavaScript的執(zhí)行線程,并確保在它完成之前沒(méi)有人能與你的程序進(jìn)行交互。如果你需要很大的延遲,甚至有可能會(huì)讓整個(gè)程序崩潰。

那么應(yīng)該怎么做呢?

事實(shí)上,也可以結(jié)合本文前面學(xué)到的技巧來(lái)制作一個(gè)不太侵入性的 sleep 方法:

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

console.log('Hello');
sleep(2000).then(() => { console.log('World!'); });

這段代碼將在控制臺(tái)上打印“Hello”,等待兩秒,然后打印“World!”在底層,我們使用setTimeout 方法在給定的毫秒數(shù)后解析一個(gè) promise。

注意,我們需要使用一個(gè) then 回調(diào)來(lái)確保第二條消息是帶有延遲的。我們還可以在第一個(gè)回調(diào)函數(shù)后面鏈?zhǔn)降靥砑痈嗷卣{(diào)函數(shù)。

這樣做是可行的,但看起來(lái)不太好看。我們可以使用async ... await來(lái)美化它:

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function delayedGreeting() {
  console.log('Hello');
  await sleep(2000);
  console.log('World!');
  await sleep(2000);
  console.log('Goodbye!');
}

delayedGreeting();

這看起來(lái)更好看,但這意味著使用 sleep 函數(shù)的任何代碼都需要被標(biāo)記為 async。

當(dāng)然,這兩種方法仍然有一個(gè)缺點(diǎn)(或特點(diǎn)),那就是它們不會(huì)暫停整個(gè)程序的執(zhí)行。只有你的函數(shù)會(huì)睡眠:

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function delayedGreeting() {
  console.log('Hello');
  await sleep(2000); // await只暫停當(dāng)前的異步函數(shù)
  console.log('World!');
}

delayedGreeting();
console.log('Goodbye!');

上面的代碼會(huì)依次打印出:

Hello
Goodbye!
World!

這樣,你可以根據(jù)需要靈活地使用不同的方法和技術(shù)來(lái)實(shí)現(xiàn)JavaScript中的延遲和異步操作。

創(chuàng)建 JS Sleep函數(shù)的最佳實(shí)踐

我們已經(jīng)探討了各種在JavaScript中引入延遲的方法。現(xiàn)在讓我們總結(jié)一下哪種方法最適合不同的場(chǎng)景,以及哪種方法通常應(yīng)該避免。

1.純粹的setTimeout

console.log('Hello');
setTimeout(() => { console.log('World!'); }, 2000);

?? 優(yōu)點(diǎn):容易理解,非阻塞。 ?? 缺點(diǎn):對(duì)異步操作的控制有限。 ?? 何時(shí)使用:適用于簡(jiǎn)單的、一次性的延遲,或基礎(chǔ)輪詢。

2.遞增的 setTimeout

setTimeout(() => { console.log('Hello'); }, 1000);
setTimeout(() => { console.log('World!'); }, 2000);

?? 優(yōu)點(diǎn):非阻塞性,易于實(shí)現(xiàn),不需要了解 promises 或 async/await。 ?? 缺點(diǎn):不適用于復(fù)雜的異步操作。沒(méi)有錯(cuò)誤處理。 ?? 何時(shí)使用:用于有時(shí)間間隔的簡(jiǎn)單序列。

3.通過(guò)循環(huán)阻塞事件循環(huán)

console.log('Hello');
const date = Date.now();
let currentDate = null;
do {
  currentDate = Date.now();
} while (currentDate - date < 2000);
console.log('World!');

?? 優(yōu)點(diǎn):模仿傳統(tǒng)的sleep行為。 ?? 缺點(diǎn):阻塞整個(gè)線程,可能會(huì)凍結(jié)UI或?qū)е鲁绦虮罎ⅰ??? 強(qiáng)烈不推薦:只有在你絕對(duì)需要暫停執(zhí)行并且意識(shí)到其中的風(fēng)險(xiǎn)時(shí)才使用。

4.使用Promises與setTimeout

const sleep = function(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}
console.log('Hello');
sleep(2000).then(() => { console.log('World!'); });

?? 優(yōu)點(diǎn):非阻塞性,對(duì)異步操作有更多的控制。 ?? 缺點(diǎn):需要理解promises。更長(zhǎng)的promise鏈可能會(huì)變得有點(diǎn)混亂。 ?? 何時(shí)使用:當(dāng)你需要更多對(duì)時(shí)間和異步操作的控制時(shí)。

5.使用async/await與Promises

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function delayedGreeting() {
  console.log('Hello');
  await sleep(2000);
  console.log('World!');
  await sleep(2000);
  console.log('Goodbye!');
}

delayedGreeting();

?? 優(yōu)點(diǎn):語(yǔ)法清晰,易于閱讀,非阻塞。 ?? 缺點(diǎn):需要理解async/await和promises。需要在模塊外部“包裝”函數(shù)。 ? 強(qiáng)烈推薦:這是最現(xiàn)代和干凈的方法,尤其是在處理多個(gè)異步操作時(shí)。

總結(jié)

JavaScript中的時(shí)序問(wèn)題是許多開(kāi)發(fā)人員頭疼的原因,你如何處理它們?nèi)Q于你想實(shí)現(xiàn)什么。

盡管在許多其他語(yǔ)言中都有 sleep 函數(shù),但我鼓勵(lì)你去接受JavaScript的異步特性,盡量不要與這門語(yǔ)言作對(duì)。當(dāng)你習(xí)慣了它,它實(shí)際上是相當(dāng)不錯(cuò)的。

責(zé)任編輯:武曉燕 來(lái)源: 大遷世界
相關(guān)推薦

2011-05-26 15:52:31

sleep()wait()

2024-10-07 08:59:47

sleepwait線程

2022-08-02 08:00:49

sleepwait釋放鎖

2022-01-06 07:03:30

Linux SleepWait

2025-04-02 08:25:00

Java開(kāi)發(fā)wait

2020-07-22 08:06:46

釋放鎖synchronize線程

2023-04-28 07:49:13

Javawaitsleep

2021-05-07 06:22:36

Pause容器源碼

2020-08-02 23:56:34

JavaScript函數(shù)代碼

2022-04-18 07:36:37

TimeUnit線程休眠

2010-03-25 09:08:50

Python模擬網(wǎng)站

2010-03-15 18:18:33

Java多線程

2009-12-21 17:48:30

WCF方法重載

2009-06-10 22:06:29

JavaScript面向?qū)ο?/a>

2011-10-19 16:21:45

2010-10-08 09:42:23

JavaScript方

2025-01-09 08:49:36

Java并發(fā)編程

2017-08-28 16:01:59

前端JavaScript學(xué)習(xí)途徑

2020-11-01 17:11:51

time.sleep暫停代碼Python

2011-06-22 15:09:34

Qt 線程 sleep
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)