1. 程式人生 > 程式設計 >javascript 使用sleep函式的常見方法詳解

javascript 使用sleep函式的常見方法詳解

本文例項講述了javascript 使用sleep函式的常見方法。分享給大家供大家參考,具體如下:

一.什麼是sleep函式?

花一點時間來聊一下sleep函式,首先什麼是sleep函式?

sleep是一種函式,他的作用是使程式暫停指定的時間,起到延時的效果。

例如:

console.log('1');
sleep(5000);
console.log('2');

控制檯輸出數字1後會間隔5秒後輸出數字2

當然上面的程式碼是不能執行的,因為js中是沒有sleep方法的。

所以這一篇文章主要介紹幾種在js中實現sleep的方式。

二.為什麼使用sleep?

看到這裡有人會問了,為什麼要使用sleep,上面的例子我可以使用setTimeout來實現啊?

因為setTimeout是通過回撥函式來實現定時任務的,所以在多工的場景下就會出現回撥巢狀:

console.time('runTime:');
setTimeout(function(){
 console.log('1')
 setTimeout(function(){
 console.log('2');
 setTimeout(function(){
  console.log('3');
  console.timeEnd('runTime:');
 },2000);
 },3000);
},2000);
// 1
// 2
// 3
// runTime:: 7013.104ms

上面的方式存在回撥巢狀的問題,我們希望有一個優雅的方式來實現上面的例子:

sleep(2000);
console.log('1');
sleep(3000);
console.log('2');
sleep(2000);
console.log('3');
...

三.實現sleep

接下來我們就分別用幾種不同的方法來實現下sleep方法

1.基於Date實現

通過死迴圈來阻止程式碼執行,同時不停比對是否超時。

function sleep(time){
 var timeStamp = new Date().getTime();
 var endTime = timeStamp + time;
 while(true){
 if (new Date().getTime() > endTime){
  return;
 } 
 }
}
console.time('runTime:');
sleep(2000);
console.log('1');
sleep(3000);
console.log('2');
sleep(2000);
console.log('3');
console.timeEnd('runTime:');
// 1
// 2
// 3
// runTime:: 7004.301ms

缺點:

以上的程式碼不會讓執行緒休眠,而是通過高負荷計算使cpu無暇處理其他任務。

這樣做的缺點是在sleep的過程中其他所有的任務都會被暫停,包括dom的渲染。

所以sleep的過程中程式會處於假死狀態,並不會去執行其他任務

2.基於Promise的sleep

為了解決ajax的回撥巢狀問題,在jQuery1.8之後支援了Promise。但是單純的Promise只是將之前的縱向巢狀改為了橫向巢狀,

最終結果是下面的程式碼:

function sleep(time){
 return new Promise(function(resolve){
 setTimeout(resolve,time);
 });
}
console.time('runTime:');
console.log('1');
sleep(1000).then(function(){
 console.log('2');
 sleep(2000).then(function(){
 console.log('3');
 console.timeEnd('runTime:');
 });
});
console.log('a');
// 1
// a
// 2
// 3
// runTime:: 3013.476ms

這其實和之前的setTimeout巢狀沒什麼區別,也很難看。

我們再次進行優化,使用ES6的Generator函式來改寫上面的例子

3.基於Generator函式的sleep

我們對sleep的執行使用Generator函式來執行,並且搭配co來進行自執行。

看程式碼:

var co = require('co');
 
function sleep(time){
 return new Promise(function(resolve){
 setTimeout(resolve,time);
 });
}
 
var run = function* (){
 console.time('runTime:');
 console.log('1');
 yield sleep(2000);
 console.log('2');
 yield sleep(1000);
 console.log('3'); 
 console.timeEnd('runTime:');
}
 
co(run);
console.log('a');
// 1
// a
// 2
// 3
// runTime:: 3004.935ms

可以看到整體的程式碼看起來不存在巢狀的關係,還是比較舒服的。

並且執行過程不會發生假死情況,不會阻塞其他任務的執行。

但是多了一個co執行器的引用,所以還是有瑕疵。

當然這不是最終版,因為ES7為我們帶來了新的解決方案。

4.基於async函式的sleep

ES7新增了async函式,async函式最大的特點就是自帶執行器,所以我們可以不借助co來實現sleep了

看程式碼:

function sleep(time){
 return new Promise((resolve) => setTimeout(resolve,time));
}
 
async function run(){
 console.time('runTime:');
 console.log('1');
 await sleep(2000);
 console.log('2');
 await sleep(1000);
 console.log('3'); 
 console.timeEnd('runTime:');
}
 
run();
console.log('a');
 
// 1
// a
// 2
// 3
// runTime:: 3009.984ms

效果和之前的一樣。

5.使用child_process(子程序)實現sleep函式

前面介紹了幾種比較簡單的sleep實現,接下來看一個比較難的實現。

原理是將sleep放在子程序中執行,不會影響其他程序,看程式碼:

var childProcess = require('child_process');
var nodeBin = process.argv[0];
 
function sleep(time) {
 childProcess.execFileSync(nodeBin,['-e','setTimeout(function() {},' + time + ');']);
 // childProcess.spawnSync(nodeBin,' + time + ');']);
}
 
console.time('runTime:');
console.log('1');
sleep(1000);
console.log('2');
sleep(2000);
console.log('3');
console.timeEnd('runTime:');
 
// 1
// 2
// 3
// runTime:: 3579.093ms

以上程式碼,是通過childProcess物件的execFileSync或者spawnSync建立一個同步程序,

在同步程序中執行定時器,定時器執行完畢後回收程序,程式繼續執行。

6.使用npm sleep包

前面的內容都是我們自己實現的,其實npm上已經有很多相關的js包了。

我們來看看他們是怎麼實現的,sleep

var sleep = require('sleep');
 
console.log('1');
console.time('runTime:');
sleep.sleep(2); //休眠2秒鐘
console.log('2');
sleep.msleep(1000); //休眠1000毫秒
console.log('3');
sleep.usleep(1000000) //休眠1000000微秒 = 1秒
console.log('4');
console.timeEnd('runTime:');
 
// 1
// 2
// 3
// 4
// runTime:: 4014.455ms

很強有沒有,sleep包是C++編寫,然後擴充套件到Node來實現sleep函式
也是一個不錯的選擇。

以上就是sleep的六種簡單實現。歡迎大家指出問題,我們一起進步。

感興趣的朋友可以使用線上HTML/CSS/JavaScript程式碼執行工具:http://tools.jb51.net/code/HtmlJsRun測試上述程式碼執行效果。

更多關於JavaScript相關內容可檢視本站專題:《JavaScript常用函式技巧彙總》、《javascript面向物件入門教程》、《JavaScript錯誤與除錯技巧總結》、《JavaScript資料結構與演算法技巧總結》及《JavaScript數學運算用法總結》

希望本文所述對大家JavaScript程式設計有所幫助。