用異步API的原因
異步的概念之所以首先在Web2.0中火起來,是因為在瀏覽器中Javascript在單線程上執行,而且他還與UI渲染公用一個線程.這意味著Javascript在執行的時候UI渲染和響應是處於停滯狀態的.為了用戶體驗更好而採取異步的方式(當然,這在所謂的單線程語言中)不阻塞主線程繼續響應用戶操作.這屬於用戶體驗的範疇.
同樣的,如果有其他語言經驗的工程師當然也明白,CPU在線程間切換是需要消耗大量的時間的(主要為上下文之間的切換和緩存),所以提高效率也是使用異步API的理由.
當然,這些並不是絕對的正確,只是人人都這麼說而已.因為如果創建多線程的開銷小於並行執行,那麼多線程的方式是首選,這時常被認為是CPU密集型的處理任務.
總之,異步IO或者說異步API可以算作Node的特色,因為它是收個大規模將異步IO應用在應用層上的平台,它力求在單線程上將資源分配得更高效.
關於Promise
這裡,本文並不打算詳細講解Promise的用法,只簡單說明Promise的一些API和試用範圍:
//結合nodejs的fs.readdir函數創建一個原生Promisevar 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('內容為:'+files); return files; //為了接著演示其他API 這裡return之後可繼續使用then定義下一步操作函數.});promiseTask.catch(function(err){ console.log('報錯為:'+err);});如何等待多個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);});這段代碼確實表現出了nodejs開發的優雅之處.
那麼問題在哪?
目前再優雅的語言依然依託於操作系統,也就是說,系統的限制依然存在:
我不知道能不能把這個錯誤解釋成文件操作句柄耗盡,但大概意思本文希望各位能夠理解,操作系統並不是可以同時打開無限多個文件.
還有這種:
這個很好理解,內存耗盡. 當然,內存限制,可以通過加入以下兩個運行參數調整:
node --max-old-space-size=8192 ./index.js #單位MB node --max-new-space-size=2048 ./index.js #單位KB
上述參數在V8初始化時生效,一旦生效不可動態變更.
很多人可能會提出,這兩個限制在其他語言中一樣存在.是的,其他語言一樣存在.
但是其他語言強大的GC或多線程的編程模型可以讓工程師們能在申請系統資源之後及時釋放.
而nodejs中雖然也可手動釋放不需要的系統資源,但真的可以做到引用程序裡的每一個操作都能及時釋放嗎?
舉個栗子: nodejs的redis包(npm install redis)並不提供同步的操作方法.
這意味著開發的過程要考慮更多的流程控制,很遺憾,單線程體系的nodejs並不擅長這個,正是因為本質上沒有多線程的概念,沒有鎖機制,也不可能包含通常意義上的信號量機制,結果就是工程師根本不知道什麼時候去手動釋放資源.
除非對自己項目有絕對的掌控權,不使用任何使用異步API的第三方包.
所以,目前的結論就是,Promise只是一種開發的技巧,了解這些,並不適用於所有開發場景.
總結
以上就是關於node.js異步API和其局限性的全部內容,希望這篇文章對大家能有所幫助。如果有疑問大家可以留言交流。