深入分析node.js的異步API和其局限性
用異步API的原因
異步的概念之所以首先在Web2.0中火起來(lái),是因?yàn)樵跒g覽器中Javascript在單線程上執(zhí)行,而且他還與UI渲染公用一個(gè)線程.這意味著Javascript在執(zhí)行的時(shí)候UI渲染和響應(yīng)是處于停滯狀態(tài)的.為了用戶體驗(yàn)更好而采取異步的方式(當(dāng)然,這在所謂的單線程語(yǔ)言中)不阻塞主線程繼續(xù)響應(yīng)用戶操作.這屬于用戶體驗(yàn)的范疇.
同樣的,如果有其他語(yǔ)言經(jīng)驗(yàn)的工程師當(dāng)然也明白,CPU在線程間切換是需要消耗大量的時(shí)間的(主要為上下文之間的切換和緩存),所以提高效率也是使用異步API的理由.
當(dāng)然,這些并不是絕對(duì)的正確,只是人人都這么說(shuō)而已.因?yàn)槿绻麆?chuàng)建多線程的開(kāi)銷小于并行執(zhí)行,那么多線程的方式是首選,這時(shí)常被認(rèn)為是CPU密集型的處理任務(wù).
總之,異步IO或者說(shuō)異步API可以算作Node的特色,因?yàn)樗鞘諅€(gè)大規(guī)模將異步IO應(yīng)用在應(yīng)用層上的平臺(tái),它力求在單線程上將資源分配得更高效.
關(guān)于Promise
這里,本文并不打算詳細(xì)講解Promise的用法,只簡(jiǎn)單說(shuō)明Promise的一些API和試用范圍:
//結(jié)合nodejs的fs.readdir函數(shù)創(chuàng)建一個(gè)原生Promise var promiseTask = new Promise(function(resolve,reject){ fs.readdir('/var/www',function(err,files){ if(!err){ resolve(files); }else{ reject(err); } }); }); promiseTask.then(function(files){ console.log('內(nèi)容為:'+files); return files; //為了接著演示其他API 這里return之后 可繼續(xù)使用then定義下一步操作函數(shù). }); promiseTask.catch(function(err){ console.log('報(bào)錯(cuò)為:'+err); });
如何等待多個(gè)Promise完成?
//接上面 promiseTask.then(function(files){ var readFilsePromiseList = files.map(function(file,index){ return new Promise(function(resolve,reject){ fs.readFile(file,'utf-8',function(err,str){ if(!err){ resolve(str) } else{ reject(err) } }); }); }); return Promise.all(readFilsePromiseList); }).then(function(fileStrArray){ console.log('所謂文件讀取完畢:'+fileStrArray); });
這段代碼確實(shí)表現(xiàn)出了nodejs開(kāi)發(fā)的優(yōu)雅之處.
那么問(wèn)題在哪?
目前再優(yōu)雅的語(yǔ)言依然依托于操作系統(tǒng),也就是說(shuō),系統(tǒng)的限制依然存在:
我不知道能不能把這個(gè)錯(cuò)誤解釋成文件操作句柄耗盡,但大概意思本文希望各位能夠理解,操作系統(tǒng)并不是可以同時(shí)打開(kāi)無(wú)限多個(gè)文件.
還有這種:
這個(gè)很好理解,內(nèi)存耗盡. 當(dāng)然,內(nèi)存限制,可以通過(guò)加入以下兩個(gè)運(yùn)行參數(shù)調(diào)整:
node --max-old-space-size=8192 ./index.js #單位MB node --max-new-space-size=2048 ./index.js #單位KB
上述參數(shù)在V8初始化時(shí)生效,一旦生效不可動(dòng)態(tài)變更.
很多人可能會(huì)提出,這兩個(gè)限制在其他語(yǔ)言中一樣存在.是的,其他語(yǔ)言一樣存在.
但是其他語(yǔ)言強(qiáng)大的GC或多線程的編程模型可以讓工程師們能在申請(qǐng)系統(tǒng)資源之后及時(shí)釋放.
而nodejs中雖然也可手動(dòng)釋放不需要的系統(tǒng)資源,但真的可以做到引用程序里的每一個(gè)操作都能及時(shí)釋放嗎?
舉個(gè)栗子:nodejs的redis包(npm install redis)并不提供同步的操作方法.
這意味著開(kāi)發(fā)的過(guò)程要考慮更多的流程控制,很遺憾,單線程體系的nodejs并不擅長(zhǎng)這個(gè),正是因?yàn)楸举|(zhì)上沒(méi)有多線程的概念,沒(méi)有鎖機(jī)制,也不可能包含通常意義上的信號(hào)量機(jī)制,結(jié)果就是工程師根本不知道什么時(shí)候去手動(dòng)釋放資源.
除非對(duì)自己項(xiàng)目有絕對(duì)的掌控權(quán),不使用任何使用異步API的第三方包.
所以,目前的結(jié)論就是,Promise只是一種開(kāi)發(fā)的技巧,了解這些,并不適用于所有開(kāi)發(fā)場(chǎng)景.
總結(jié)
以上就是關(guān)于node.js異步API和其局限性的全部?jī)?nèi)容,希望這篇文章對(duì)大家能有所幫助。如果有疑問(wèn)大家可以留言交流。
相關(guān)文章
win7下安裝配置node.js+express開(kāi)發(fā)環(huán)境
windows7下安裝nodejs及框架express,從誕生至今一直被熱捧,筆者最近也裝了個(gè)環(huán)境打算了解一下。安裝步驟簡(jiǎn)單比較簡(jiǎn)單,這里分享給大家,希望大家能夠喜歡。2015-12-12輕松創(chuàng)建nodejs服務(wù)器(9):實(shí)現(xiàn)非阻塞操作
這篇文章主要介紹了輕松創(chuàng)建nodejs服務(wù)器(9):實(shí)現(xiàn)非阻塞操作,本系列文章會(huì)教你一步一步創(chuàng)建一個(gè)完整的服務(wù)器,要的朋友可以參考下2014-12-12node.js學(xué)習(xí)筆記之koa框架和簡(jiǎn)單爬蟲(chóng)練習(xí)
這篇文章主要介紹了node.js學(xué)習(xí)筆記之koa框架和簡(jiǎn)單爬蟲(chóng)練習(xí),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-12-12Nodejs如何使用http標(biāo)準(zhǔn)庫(kù)異步加載https請(qǐng)求json數(shù)據(jù)
這篇文章主要介紹了Nodejs如何使用http標(biāo)準(zhǔn)庫(kù)異步加載https請(qǐng)求json數(shù)據(jù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09Node連接MySQL并封裝其增刪改查的實(shí)現(xiàn)代碼
本文主要介紹了Node連接MySQL并封裝其增刪改查的實(shí)現(xiàn)代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12Node 使用express-http-proxy 做api網(wǎng)關(guān)的實(shí)現(xiàn)
這篇文章主要介紹了Node 使用express-http-proxy 做api網(wǎng)關(guān)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10解決淘寶cnpm 安裝后cnpm不是內(nèi)部或外部命令的問(wèn)題
今天小編就為大家分享一篇解決淘寶cnpm 安裝后cnpm不是內(nèi)部或外部命令的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-05-05node.js中fs文件系統(tǒng)模塊的使用方法實(shí)例詳解
這篇文章主要介紹了node.js中fs文件系統(tǒng)模塊的使用方法,結(jié)合實(shí)例形式詳細(xì)分析了node.js fs文件系統(tǒng)模塊各種常見(jiàn)方法的基本使用技巧與相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2020-02-02