產(chǎn)生問題的經(jīng)過
手頭有個項目,遇到一個問題焦辅,nodejs中通過執(zhí)行shell命令來執(zhí)行本地程序杭棵,我希望是先執(zhí)行本地程序婚惫,得到返回結(jié)果,做出if判斷魂爪。
所以我將執(zhí)行本地程序的代碼放在了if判斷的前面先舷,在我的印象中nodejs基于js,js是單線程滓侍,同步執(zhí)行蒋川,所以這段程序一定是按順序執(zhí)行。但結(jié)果是得不到返回結(jié)果總出錯撩笆。
解決問題
問題得到解決捺球,兩步:
1.查看官方文檔,由于我做的是火狐擴展夕冲,我參考的是MDN官方文檔
2.調(diào)試氮兵,不斷地調(diào)試,動手比空想強歹鱼。
這里執(zhí)行本地程序時間長泣栈,nodejs這里是異步執(zhí)行,所以還沒得到返回結(jié)果就進行了判斷弥姻。
解決的辦法是把判斷程序放在了child_process.exec('shell', callback)中的回調(diào)函數(shù)callback中南片。(其實nodejs官方文檔中支持execSync直接支持同步執(zhí)行,可惜火狐擴展中不支持這個方法庭敦。)
新的問題
1.nodejs執(zhí)行異步的原理铃绒,js是否能執(zhí)行異步,單線程如何實現(xiàn)異步螺捐?
2.回調(diào)函數(shù)是什么颠悬,如何利用它執(zhí)行異步?
解決新的問題
1.nodejs的單線程執(zhí)行實際上只是針對我們所寫的js代碼而言的定血,它的底層實際上用的是c/c++赔癌,遇到I/O這樣的耗時量大的底層會開啟一個線程執(zhí)行一個回調(diào)函數(shù)。舉個栗子澜沟。上一幅圖具體來說灾票,當(dāng)我們調(diào)用 fs.open 時,Node.js 通過 process.binding 調(diào)用 C/C++ 層面的 Open 函數(shù)茫虽,然后通過它調(diào)用 Libuv 中的具體方法 uv_fs_open刊苍,最后執(zhí)行的結(jié)果通過回調(diào)的方式傳回既们,完成流程。Libuv就是用c++編寫的底層正什。
而這種異步模式下啥纸,實現(xiàn)同步,就可以用以上提到的回調(diào)函數(shù)的方法來寫同步婴氮。文章參考1斯棒,文章參考2.
2.js是毫無疑問的單線程,同一時間段只能完成一件事情主经,但這并不代表它沒有辦法實現(xiàn)異步荣暮,異步和單線程并沒有直接的關(guān)系,實際上有好幾種方法能夠?qū)崿F(xiàn)罩驻,可以參考文章穗酥。
3.回調(diào)函數(shù)是指是指通過函數(shù)參數(shù)傳遞到其它代碼的,某一塊可執(zhí)行代碼的引用惠遏。即可以簡單理解為是函數(shù)被當(dāng)作參數(shù)傳入另外一個函數(shù)當(dāng)中砾跃,并在那個函數(shù)中被調(diào)用。
從以上也可以看到爽哎,回調(diào)只是一種執(zhí)行方法蜓席,既有異步回調(diào)器一,也有同步回調(diào)课锌。舉個簡單栗子:
var b = function (){
//執(zhí)行相關(guān)的代碼
}
var a = function (b){
//執(zhí)行相關(guān)的代碼
b();
}
a(b);
這是同步回調(diào)。
如果f1是一個很耗時的任務(wù)祈秕,f2需要f1的結(jié)果執(zhí)行渺贤,可以把它們寫成
function f1(callback){
setTimeout(function () {
// f1的任務(wù)代碼
callback();
}, 1000);
}
f1(f2);
這樣js會先執(zhí)行其他的主要邏輯,js線程空閑一秒之后再執(zhí)行這個操作请毛。從而實現(xiàn)異步志鞍。
文章參考
總結(jié)
寫下這篇文章的過程其實也是我弄清楚其中原委的過程,這只是一個很細節(jié)的問題方仿,但是思考的過程卻十分漫長固棚。共勉。