使用JS實現(xiàn)一個Sleep函數(shù)的示例代碼
前言
我們都是 JavaScript 是一個單線程語言,單線程有它的好處也有它的壞處。在我們熟知的如 Java、C++等語言中,都提供了一個叫做 Sleep 的內(nèi)置函數(shù)。這個函數(shù)的作用就和它的名字一樣:睡眠。
假設我們有這樣一個場景:我們需要在項目運行起來后的十分鐘之后去執(zhí)行一段代碼,這段代碼可以是符合你業(yè)務場景的任何代碼,比如查看內(nèi)存占用多少等等。
在 Java 這類語言中,可以直接使用 Sleep 這個內(nèi)置函數(shù)實現(xiàn)這個需求,Sleep 函數(shù)會讓出或者停下當前線程,讓其它程序先執(zhí)行,到底指定時間后在繼續(xù)執(zhí)行。
然而我們的 JavaScript 沒有提供 sleep 內(nèi)置函數(shù),大致就是因為單線程的原因把!所以說我們可以嘗試著自己封裝一個!
1.目標分析
既然我們要去實現(xiàn)一個 sleep 函數(shù),那么我們肯定要先有一個比較實際的場景,這樣才好開展工作。
假設我們有如下一段代碼:
<script>
function fnA() {
console.log('A');
}
function fnB() {
console.log('B');
}
function fnC() {
console.log('C');
}
// 實現(xiàn)目標
fnA(); // 1 秒后打印
fnB(); // 2 秒后打印
fnC(); // 3 秒后打印
</script>上段代碼非常簡單,我們的目的就是為了讓它們幾個分別間隔 1 秒打印,需求非常簡單,實現(xiàn)起來也很容易,可能有些小伙伴直接想到了 setTimeout。
確實,setTimeout 可以實現(xiàn)我們的需求,比如下面的代碼:
setTimeout(fnA, 1000); setTimeout(fnB, 2000); setTimeout(fnC, 3000);
定時器確實可以滿足我們的需求,但是如果項目中到處些定時器的可能會讓人很疑惑,所以我們有必要進行封裝,寫一個自己的 sleep 函數(shù),大家多看幾種實現(xiàn)方式應該就會豁然開朗了。
2.setTimeout 封裝
這是大家最容易想到也是最暴力的一種方式,畢竟一提到延時執(zhí)行大家都會想到定時器,所我們直接利用 setTimeout 的這個特性來實現(xiàn)我們的 sleep 函數(shù)。
代碼如下:
<script>
function fnA() {
console.log('A');
}
function fnB() {
console.log('B');
}
function fnC() {
console.log('C');
}
// sleep 函數(shù)
function sleep(fun, time) {
setTimeout(() => {
fun();
}, time);
}
sleep(fnA, 1000); // 1 秒后輸出 A
sleep(fnB, 2000); // 2 秒后輸出 B
sleep(fnC, 3000); // 3 秒后輸出 C
</script>這是最原始的一種方式,其實本質(zhì)就是定時器,只不過我們封裝成一個函數(shù)罷了。
這種實現(xiàn)方式有如下優(yōu)缺點:
優(yōu)點:
簡單易實現(xiàn),兼容性好,畢竟只是用了 setTimeout,而且非常好理解。
缺點:
我們需要傳入回調(diào)函數(shù)的方式進去,如果函數(shù)里面有多回調(diào)函數(shù)可能不太好理解。另外一點就是它不會阻塞同步任務,比如下面代碼的輸出結(jié)果:
sleep(fnA, 1000);
console.log('E');
sleep(fnB, 2000);
console.log('G');
sleep(fnC, 3000);輸出結(jié)果:

在有些場景下我們可能需要 sleep 函數(shù)會阻塞代碼,依次執(zhí)行,這個時候這種封裝就滿足不了了。
3.Promise 封裝
promise 是 ES6 提出的一種異步解決方案,它和 setTimeout 一樣,都可以實現(xiàn)異步,區(qū)別在于 promise 解決了回調(diào)函數(shù)的問題,它可以實現(xiàn)鏈式調(diào)用,我們可以接觸 promise 來實現(xiàn) sleep 函數(shù)。
代碼如下:
<script>
function fnA() {
console.log('A');
}
function fnB() {
console.log('B');
}
function fnC() {
console.log('C');
}
// sleep 函數(shù)--Promise 版本
function sleep(time) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, time);
});
}
sleep(1000).then(fnA); // 1 秒后輸出 A
sleep(2000).then(fnB); // 2 秒后輸出 B
sleep(3000).then(fnC); // 3 秒后輸出 C
</script>上段代碼中利用 promise 實現(xiàn)了 sleep 函數(shù),其實是 promise 和 setTimeout 的結(jié)合,不過上段代碼中我們可以進行鏈式調(diào)用了,不必再往 sleep 函數(shù)中傳入回調(diào)函數(shù)了。
優(yōu)點:
不用再傳入回調(diào)函數(shù),采用鏈式調(diào)用。
缺點:
仍未解決阻塞問題,依然會先執(zhí)行同步任務,代碼如下:
sleep(1000).then(fnA); // 1 秒后輸出 A
console.log('E');
sleep(2000).then(fnB); // 2 秒后輸出 B
console.log('G');
sleep(3000).then(fnC); // 3 秒后輸出 C輸出結(jié)果:

4.async/await
前面兩個封裝中我們一直提及阻塞問題,那么既然我們使用了 promise,我們就很有必要將 async/await 拿出來使用,它們可以完美的阻塞我們的代碼,然我們的代碼依次執(zhí)行。
代碼如下:
<script>
function fnA() {
console.log('A');
}
function fnB() {
console.log('B');
}
function fnC() {
console.log('C');
}
// sleep 函數(shù)--Promise 版本
function sleep(time) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, time);
});
}
async function sleepTest() {
fnA(); // 輸出 A
await sleep(1000); // 睡眠 1 秒
console.log('E'); // 輸出 E
fnB(); // 輸出 B
await sleep(1000); // 睡眠 1 秒
fnC(); // 輸出 C
await sleep(1000); // 睡眠 1 秒
console.log('G'); // 輸出 G
}
sleepTest();
</script>
輸出結(jié)果:

上段代碼中我們封裝的 sleep 函數(shù)并沒有改變,只是我們調(diào)用 sleep 函數(shù)的使用采用了 async/await 的方式調(diào)用,這就很好的解決了我們程序沒有阻塞的額問題了。
總結(jié)
實現(xiàn) sleep 函數(shù)其實非常簡單,主要是理解 JavaScript 中異步執(zhí)行情況。雖然上面的代碼中使用 await sleep()的方式看起來最像一個真正的 sleep 函數(shù),但是凡事都有兩面性,比如我們有些場景只是需要一定時間后執(zhí)行某個函數(shù),不想阻塞代碼的執(zhí)行,這個時候 setTimeout 和 promise 都是非常好的選擇,但有時候我們就是需要阻塞代碼的執(zhí)行,比如后面的代碼用到了前面這個函數(shù)的返回結(jié)果,這個時候 async/await 就是一個很好的選擇了。
到此這篇關(guān)于使用JS實現(xiàn)一個Sleep函數(shù)的文章就介紹到這了,更多相關(guān)js Sleep函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用 JavaScript 進行函數(shù)式編程 (一) 翻譯
本文是函數(shù)式編程系列的第一篇文章。這里我會簡要介紹一下編程范式,然后會直接介紹使用 Javascript 進行函數(shù)式編程的概念,因為 JavsScript 是最被認可的函數(shù)式程序語言之一。我們鼓勵讀者通過參考資料部分進一步了解這一迷人的概念2015-10-10
JavaScript String 對象常用方法總結(jié)
下面小編就為大家?guī)硪黄狫avaScript String 對象常用方法總結(jié)。小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考2016-04-04
JavaScript實現(xiàn)讀取條碼中的二進制數(shù)據(jù)
條碼是一種以機器可讀的可視形式表示數(shù)據(jù)的方法,我們可以從條碼獲取二進制數(shù)據(jù),并通過不同方法去讀碼,下面我們就來看看如何實現(xiàn)讀取條碼中的二進制數(shù)據(jù)吧2024-03-03

