NodeJS如何實(shí)現(xiàn)同步的方法示例
前言
眾所周知,異步是得天獨(dú)厚的特點(diǎn)和優(yōu)勢(shì),但同時(shí)在程序中同步的需求(比如控制程序的執(zhí)行順序?yàn)椋篺unc1 -> func2 ->func3 )也是很常見的。
下面這篇文章主要介紹了關(guān)于NodeJS實(shí)現(xiàn)同步的相關(guān)內(nèi)容,NodeJS被打上了單線程、非阻塞、事件驅(qū)動(dòng)…..等標(biāo)簽。 在單線程的情況下,是無法開啟子線程的。經(jīng)過了很久的研究,發(fā)現(xiàn)并沒有thread函數(shù)!??!但是有時(shí)候,我們確實(shí)需要“多線程”處理事務(wù)。nodeJS有兩個(gè)很基礎(chǔ)的api:setTimeout和setInterval。這兩個(gè)函數(shù)都能實(shí)現(xiàn)“異步”。 nodeJS的異步實(shí)現(xiàn):nodeJS有一個(gè)任務(wù)隊(duì)列,在使用setInterval函數(shù)的時(shí)候,會(huì)每隔特定的時(shí)間向該任務(wù)隊(duì)列增加任務(wù),從而實(shí)現(xiàn)“多任務(wù)”處理。但是,“特定的時(shí)間”不代表是具體的時(shí)間,也有可能是會(huì)大于我們?cè)O(shè)定的時(shí)間,也有可能小于。
我們跑跑下面代碼塊
setInterval(function() { console.log(new Date().getTime()); }, 1000);
輸出的結(jié)果如下:
1490531390640
1490531391654
1490531392660
1490531393665
1490531394670
1490531395670
1490531396672
1490531397675
......
我們可以看到,所有的時(shí)間間隔都是不一樣的。時(shí)間的偏移不僅包含了間隔的1s,還包含了console.log()
的耗時(shí),以及new Date()的耗時(shí)。在大量的數(shù)據(jù)統(tǒng)計(jì)下,時(shí)間間隔近似于1s。
問題來了,setInterval是能實(shí)現(xiàn)多任務(wù)的效果,但是怎樣才能實(shí)現(xiàn)任務(wù)之間的同步操作呢?
這里實(shí)現(xiàn)的方法是通過回調(diào)函數(shù)實(shí)現(xiàn)的。
function a(callback) { // 模擬任務(wù)a耗時(shí) setTimeout(function() { console.log("task a end!"); // 回調(diào)任務(wù)b callback(); }, 3000); }; function b() { setTimeout(function() { console.log("task b end!"); }, 5000); } a(b);
這里舉了一個(gè)很簡(jiǎn)單的例子,就是將b方法的實(shí)現(xiàn)賦值給a方法的callback函數(shù)從而實(shí)現(xiàn)函數(shù)回調(diào),但是會(huì)有個(gè)問題。假設(shè)a方法依賴于b方法,b方法依賴于c方法,c方法依賴于d方法…..也就意味著每個(gè)方法的實(shí)現(xiàn)都需要持有上一個(gè)方法的實(shí)例,從而實(shí)現(xiàn)回調(diào)。
function a(b, c, d) { console.log("hello a"); b(c, d); }; function b(c, d) { console.log("hello b"); c(d); }; function c(d) { console.log("hello c"); d() }; function d() { console.log("hello d"); }; a(b, c, d);
輸出結(jié)果
hello a
hello b
hello c
hello d
如果回調(diào)函數(shù)寫的多了,會(huì)造成代碼特別特別惡心。
如果有類似于sync的函數(shù)能讓任務(wù)順序執(zhí)行就更好了。終于找到了async這個(gè)庫(kù) $ npm instanll async
async = require("async"); a = function (callback) { // 延遲5s模擬耗時(shí)操作 setTimeout(function () { console.log("hello world a"); // 回調(diào)給下一個(gè)函數(shù) callback(null, "function a"); }, 5000); }; b = function (callback) { // 延遲1s模擬耗時(shí)操作 setTimeout(function () { console.log("hello world b"); // 回調(diào)給下一個(gè)函數(shù) callback(null, "function b"); }, 1000); }; c = function (callback) { console.log("hello world c"); // 回調(diào)給下一個(gè)函數(shù) callback(null, "function c"); }; // 根據(jù)b, a, c這樣的順序執(zhí)行 async.series([b, a, c], function (error, result) { console.log(result); });
注釋基本能夠很好的理解了,我們看看輸出
hello world b
hello world a
hello world c
[ 'function b', 'function a', 'function c' ]
上面的基本async模塊的實(shí)現(xiàn)的如果了解更多關(guān)于async模塊的使用,可以點(diǎn)擊:查看詳情
其實(shí)nodeJS基本api也提供了異步實(shí)現(xiàn)同步的方式。基于Promise+then的實(shí)現(xiàn)
sleep = function (time) { return new Promise(function () { setTimeout(function () { console.log("end!"); }, time); }); }; console.log(sleep(3000));
輸出結(jié)果為:
Promise { <pending> }
end!
可以看出來,這里返回了Promise對(duì)象,直接輸出Promise對(duì)象的時(shí)候,會(huì)輸出該對(duì)象的狀態(tài),只有三種:PENDING、FULFILLED、REJECTED。字面意思很好理解。也就是說Promise有可能能實(shí)現(xiàn)我們異步任務(wù)同步執(zhí)行的功能。我們先用Promise+then結(jié)合起來實(shí)現(xiàn)異步任務(wù)同步操作。
sleep = function () { return new Promise(function (resolve, reject) { setTimeout(function () { console.log("start!"); resolve(); }, 1000); }) .then(function () { setTimeout(function () { console.log("end!"); }, 2000); }) .then(function () { console.log("end!!"); }) }; console.log(sleep(1000));
輸出結(jié)果:
Promise { <pending> }
start!
end!!
end!
在new Promise任務(wù)執(zhí)行完后,調(diào)用了resolve才會(huì)執(zhí)行所有的then函數(shù),并且這些then函數(shù)是異步執(zhí)行的。由輸出結(jié)果可以知道。(如果所有then是順序執(zhí)行的應(yīng)該是end! -> end!!)。但是上述也做到了兩個(gè)異步任務(wù)之間順序執(zhí)行了。
不過,還有更加優(yōu)雅的方式:使用async+await。
display = function(time, string) { return new Promise(function (resovle, reject) { setTimeout(function () { console.log(string); resovle(); }, time) }); }; // 執(zhí)行順序:b a c fn = async function () { // 會(huì)造成阻塞 await display(5000, "b"); await display(3000, "a"); await display(5000, "c"); }();
輸出結(jié)果:
b
a
c
由于這里時(shí)間輸出比較尷尬,只能通過我們來感知,本人通過個(gè)人“感知”知道了在display b過度到display a的時(shí)候大概用了3s,再過度到display c的時(shí)候大概用了5s
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
Nodejs實(shí)現(xiàn)爬蟲抓取數(shù)據(jù)實(shí)例解析
這篇文章主要介紹了Nodejs實(shí)現(xiàn)爬蟲抓取數(shù)據(jù)實(shí)例解析,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2018-07-07防止Node.js中錯(cuò)誤導(dǎo)致進(jìn)程阻塞的辦法
Node.js我們用到非常的多了,如果我們開發(fā)不當(dāng)可能因錯(cuò)誤導(dǎo)致進(jìn)程阻塞問題,對(duì)于進(jìn)程阻塞問題一直是個(gè)頭痛的事情,今天我們一起來看一篇關(guān)于Node.js防止錯(cuò)誤導(dǎo)致的進(jìn)程阻塞示例,下面一起來看看。2016-08-08node express如何實(shí)現(xiàn)json轉(zhuǎn)Excel
這篇文章主要介紹了node express如何實(shí)現(xiàn)json轉(zhuǎn)Excel問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08nodejs個(gè)人博客開發(fā)第一步 準(zhǔn)備工作
這篇文章主要為大家詳細(xì)介紹了nodejs個(gè)人博客開發(fā)的準(zhǔn)備工作,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04