使用JS實(shí)現(xiàn)一個(gè)Sleep函數(shù)的示例代碼
前言
我們都是 JavaScript
是一個(gè)單線程語(yǔ)言,單線程有它的好處也有它的壞處。在我們熟知的如 Java
、C++
等語(yǔ)言中,都提供了一個(gè)叫做 Sleep
的內(nèi)置函數(shù)。這個(gè)函數(shù)的作用就和它的名字一樣:睡眠。
假設(shè)我們有這樣一個(gè)場(chǎng)景:我們需要在項(xiàng)目運(yùn)行起來(lái)后的十分鐘之后去執(zhí)行一段代碼,這段代碼可以是符合你業(yè)務(wù)場(chǎng)景的任何代碼,比如查看內(nèi)存占用多少等等。
在 Java
這類語(yǔ)言中,可以直接使用 Sleep
這個(gè)內(nèi)置函數(shù)實(shí)現(xiàn)這個(gè)需求,Sleep
函數(shù)會(huì)讓出或者停下當(dāng)前線程,讓其它程序先執(zhí)行,到底指定時(shí)間后在繼續(xù)執(zhí)行。
然而我們的 JavaScript
沒(méi)有提供 sleep
內(nèi)置函數(shù),大致就是因?yàn)閱尉€程的原因把!所以說(shuō)我們可以嘗試著自己封裝一個(gè)!
1.目標(biāo)分析
既然我們要去實(shí)現(xiàn)一個(gè) sleep
函數(shù),那么我們肯定要先有一個(gè)比較實(shí)際的場(chǎng)景,這樣才好開(kāi)展工作。
假設(shè)我們有如下一段代碼:
<script> function fnA() { console.log('A'); } function fnB() { console.log('B'); } function fnC() { console.log('C'); } // 實(shí)現(xiàn)目標(biāo) fnA(); // 1 秒后打印 fnB(); // 2 秒后打印 fnC(); // 3 秒后打印 </script>
上段代碼非常簡(jiǎn)單,我們的目的就是為了讓它們幾個(gè)分別間隔 1
秒打印,需求非常簡(jiǎn)單,實(shí)現(xiàn)起來(lái)也很容易,可能有些小伙伴直接想到了 setTimeout
。
確實(shí),setTimeout
可以實(shí)現(xiàn)我們的需求,比如下面的代碼:
setTimeout(fnA, 1000); setTimeout(fnB, 2000); setTimeout(fnC, 3000);
定時(shí)器確實(shí)可以滿足我們的需求,但是如果項(xiàng)目中到處些定時(shí)器的可能會(huì)讓人很疑惑,所以我們有必要進(jìn)行封裝,寫(xiě)一個(gè)自己的 sleep
函數(shù),大家多看幾種實(shí)現(xiàn)方式應(yīng)該就會(huì)豁然開(kāi)朗了。
2.setTimeout 封裝
這是大家最容易想到也是最暴力的一種方式,畢竟一提到延時(shí)執(zhí)行大家都會(huì)想到定時(shí)器,所我們直接利用 setTimeout
的這個(gè)特性來(lái)實(shí)現(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>
這是最原始的一種方式,其實(shí)本質(zhì)就是定時(shí)器,只不過(guò)我們封裝成一個(gè)函數(shù)罷了。
這種實(shí)現(xiàn)方式有如下優(yōu)缺點(diǎn):
優(yōu)點(diǎn):
簡(jiǎn)單易實(shí)現(xiàn),兼容性好,畢竟只是用了 setTimeout
,而且非常好理解。
缺點(diǎn):
我們需要傳入回調(diào)函數(shù)的方式進(jìn)去,如果函數(shù)里面有多回調(diào)函數(shù)可能不太好理解。另外一點(diǎn)就是它不會(huì)阻塞同步任務(wù),比如下面代碼的輸出結(jié)果:
sleep(fnA, 1000); console.log('E'); sleep(fnB, 2000); console.log('G'); sleep(fnC, 3000);
輸出結(jié)果:
在有些場(chǎng)景下我們可能需要 sleep
函數(shù)會(huì)阻塞代碼,依次執(zhí)行,這個(gè)時(shí)候這種封裝就滿足不了了。
3.Promise 封裝
promise
是 ES6
提出的一種異步解決方案,它和 setTimeout
一樣,都可以實(shí)現(xiàn)異步,區(qū)別在于 promise
解決了回調(diào)函數(shù)的問(wèn)題,它可以實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用,我們可以接觸 promise
來(lái)實(shí)現(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
實(shí)現(xiàn)了 sleep
函數(shù),其實(shí)是 promise
和 setTimeout
的結(jié)合,不過(guò)上段代碼中我們可以進(jìn)行鏈?zhǔn)秸{(diào)用了,不必再往 sleep
函數(shù)中傳入回調(diào)函數(shù)了。
優(yōu)點(diǎn):
不用再傳入回調(diào)函數(shù),采用鏈?zhǔn)秸{(diào)用。
缺點(diǎn):
仍未解決阻塞問(wèn)題,依然會(huì)先執(zhí)行同步任務(wù),代碼如下:
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
前面兩個(gè)封裝中我們一直提及阻塞問(wèn)題,那么既然我們使用了 promise
,我們就很有必要將 async/await
拿出來(lái)使用,它們可以完美的阻塞我們的代碼,然我們的代碼依次執(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ù)并沒(méi)有改變,只是我們調(diào)用 sleep
函數(shù)的使用采用了 async/await
的方式調(diào)用,這就很好的解決了我們程序沒(méi)有阻塞的額問(wèn)題了。
總結(jié)
實(shí)現(xiàn) sleep
函數(shù)其實(shí)非常簡(jiǎn)單,主要是理解 JavaScript
中異步執(zhí)行情況。雖然上面的代碼中使用 await sleep()
的方式看起來(lái)最像一個(gè)真正的 sleep
函數(shù),但是凡事都有兩面性,比如我們有些場(chǎng)景只是需要一定時(shí)間后執(zhí)行某個(gè)函數(shù),不想阻塞代碼的執(zhí)行,這個(gè)時(shí)候 setTimeout
和 promise
都是非常好的選擇,但有時(shí)候我們就是需要阻塞代碼的執(zhí)行,比如后面的代碼用到了前面這個(gè)函數(shù)的返回結(jié)果,這個(gè)時(shí)候 async/await
就是一個(gè)很好的選擇了。
到此這篇關(guān)于使用JS實(shí)現(xiàn)一個(gè)Sleep函數(shù)的文章就介紹到這了,更多相關(guān)js Sleep函數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
左右懸浮可分組的網(wǎng)站QQ在線客服代碼(可謂經(jīng)典)
QQ在線客服在每一個(gè)web開(kāi)發(fā)人員的記憶里都是一個(gè)經(jīng)典,既然是經(jīng)典,也就是必不可少,那就應(yīng)該很好的呈現(xiàn)出來(lái),本文整理了一些左右懸浮可分組的網(wǎng)站QQ在線客服代碼,需要的朋友可以了解下2012-12-12基于JavaScript實(shí)現(xiàn)類似于百度學(xué)術(shù)高級(jí)檢索功能
這篇文章主要介紹了基于JavaScript實(shí)現(xiàn)類似于百度學(xué)術(shù)高級(jí)檢索功能 的相關(guān)資料,需要的朋友可以參考下2016-03-03JavaScript實(shí)現(xiàn)與使用發(fā)布/訂閱模式詳解
這篇文章主要介紹了JavaScript實(shí)現(xiàn)與使用發(fā)布/訂閱模式,較為詳細(xì)的分析了發(fā)布/訂閱模式的概念、原理并結(jié)合實(shí)例形式分析了javascript實(shí)現(xiàn)與使用發(fā)布/訂閱模式的相關(guān)操作技巧,需要的朋友可以參考下2019-01-01JavaScript函數(shù)中的防抖與節(jié)流原生實(shí)現(xiàn)及第三方庫(kù)的使用
當(dāng)你頻繁的觸發(fā)用戶界面時(shí),會(huì)不停的觸發(fā)事件處理函數(shù),可能導(dǎo)致界面卡頓,瀏覽器奔潰,頁(yè)面空白等情況,而解決這一問(wèn)題的,正是函數(shù)節(jié)流與函數(shù)防抖,所以本文將給大家介紹一下JavaScript函數(shù)中的防抖與節(jié)流原生實(shí)現(xiàn)及第三方庫(kù)的使用,需要的朋友可以參考下2023-10-10微信小程序自定義組件傳值 頁(yè)面和組件相互傳數(shù)據(jù)操作示例
這篇文章主要介紹了微信小程序自定義組件傳值 頁(yè)面和組件相互傳數(shù)據(jù)操作,結(jié)合實(shí)例形式分析了微信小程序常見(jiàn)傳值操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2019-05-05JavaScript給url網(wǎng)址進(jìn)行encode編碼的方法
這篇文章主要介紹了JavaScript給url網(wǎng)址進(jìn)行encode編碼的方法,實(shí)例分析了javascript中encodeURIComponent函數(shù)的使用技巧,需要的朋友可以參考下2015-03-03javascript中定義私有方法說(shuō)明(private method)
本篇文章主要是對(duì)javascript中定義私有方法(private method)進(jìn)行了介紹,需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助2014-01-01