1.node特點(diǎn)
高性能web服務(wù)器的要點(diǎn):事件驅(qū)動(dòng)、非阻塞I/O
- 單線程
單線程的優(yōu)點(diǎn)在于:- 不用在意狀態(tài)同步問(wèn)題
- 沒(méi)有死鎖的存在
- 沒(méi)有線程上下文交換帶來(lái)的性能上的開(kāi)銷
單線程的缺點(diǎn): - 無(wú)法利用多CPU
- 錯(cuò)誤會(huì)引起整個(gè)應(yīng)用退出羊赵,應(yīng)用的健壯性值得考驗(yàn)
- 大量計(jì)算占用CPU導(dǎo)致無(wú)法繼續(xù)調(diào)用異步I/O
使用子進(jìn)程來(lái)解決單線程中大量計(jì)算的問(wèn)題鹉动,通過(guò)將計(jì)算分發(fā)到各個(gè)子進(jìn)程众弓,可以將大量計(jì)算分解掉睦裳,然后通過(guò)進(jìn)程之間的事件消息來(lái)傳遞結(jié)果
- 分布式應(yīng)用
數(shù)據(jù)平臺(tái)在一個(gè)數(shù)據(jù)庫(kù)集群中去尋找需要的數(shù)據(jù)赫悄,阿里巴巴開(kāi)發(fā)的中間層應(yīng)用NodeFox
披坏,將數(shù)據(jù)庫(kù)集群做了劃分和映射态坦,查詢調(diào)用依舊是針對(duì)單張表進(jìn)行SQL查詢,中間層分解查詢SQL棒拂,并行地去多臺(tái)數(shù)據(jù)庫(kù)中獲取數(shù)據(jù)并合并
2.CommonJS規(guī)范
所有代碼都運(yùn)行在模塊作用域伞梯,不會(huì)污染全局作用域
模塊可以多次加載玫氢,但只會(huì)第一次加載時(shí)運(yùn)行一次,然后運(yùn)行結(jié)果會(huì)被緩存
模塊的加載順序谜诫,按照其在代碼中出現(xiàn)的順序
與AMD規(guī)范的區(qū)別
require是同步的漾峡,在服務(wù)端所有的模塊都存放在本地,可以同步加載完成喻旷,但是在瀏覽器端生逸,所有的模塊都在服務(wù)器端,等待時(shí)間取決于網(wǎng)速且预,所以只能采用異步加載的策略槽袄,相當(dāng)于異步地去加載模塊,模塊內(nèi)的代碼就是加載完成后的回調(diào)函數(shù)相互引用問(wèn)題
不會(huì)造成死循環(huán)锋谐,node會(huì)盡可能地去引用遍尺,如果引用不存在,就會(huì)給一個(gè)空的object涮拗,先加載a時(shí)乾戏,去加載b,在b中加載a時(shí)三热,應(yīng)為a還沒(méi)有導(dǎo)出屬性鼓择,因此b中應(yīng)用的a就是一個(gè)空對(duì)象,b的后續(xù)代碼中可能會(huì)報(bào)錯(cuò)-
模塊編譯
每個(gè)文件模塊都是一個(gè)module對(duì)象康铭,有id惯退,exports赌髓,parent从藤,children屬性。- js模塊的編譯
在編譯過(guò)程中锁蠕,node對(duì)獲取的js文件進(jìn)行了頭尾包裝:
- js模塊的編譯
(function(exports, require, module, __filename, __dirname){
var math=require('math');
exports.area=function(){
};
});
包裝后的代碼會(huì)返回一個(gè)function對(duì)象夷野,會(huì)將模塊對(duì)象的exports屬性,require方法荣倾,module模塊對(duì)象悯搔,以及文件路徑和文件目錄傳遞給這個(gè)function來(lái)執(zhí)行
不能直接重寫(xiě)
3.webpack特性
- 具有requirejs和browserify的功能,即是一個(gè)模塊打包器舌仍,也是一個(gè)模塊加載器
- 對(duì)CommonJS妒貌、AMD、ES6語(yǔ)法做了兼容
- 對(duì)js铸豁,css灌曙,圖片資源都支持打包
- 具有插件和加載器的機(jī)制
- 將代碼切割成不同的chunk,實(shí)現(xiàn)按需加載节芥,降低初始化時(shí)間
- 使用異步IO并具有多級(jí)緩存在刺,很快且在增量編譯上更快
4.異步編程
- 偏函數(shù)
通過(guò)指定部分參數(shù)來(lái)產(chǎn)生一個(gè)新的定制函數(shù)的形式就是偏函數(shù)
//通過(guò)初始構(gòu)造函數(shù)來(lái)判斷類型
function isType(type){
return function(obj){
return Object.prototype.toString.call(obj)==='[object '+type+']';
}
}
var isString=isType('String');
console.log(isString('red'));
console.log(isString(new String('blue')));
//函數(shù)執(zhí)行多次后才會(huì)真正執(zhí)行的函數(shù)
function after(times,func){
if(times<=0){
return func();
}
return function(){
if(--times<1){
return func.apply(this,arguments);
}
}
}
var ready=after(3,function(){
console.log('red');
});
工作原理
js線程相當(dāng)于一個(gè)分配任務(wù)和處理結(jié)果的大管家逆害,IO線程池里的各個(gè)IO線程都是小二,js線程無(wú)法承擔(dān)過(guò)多的細(xì)節(jié)性任務(wù)蚣驼,如果承擔(dān)過(guò)多魄幕,會(huì)影響到任務(wù)的調(diào)度,盡量使用非阻塞IO
nodejs更適合處理IO密集問(wèn)題異常處理
異步IO中實(shí)現(xiàn)主要包含提交請(qǐng)求和處理結(jié)果兩個(gè)階段颖杏,可能在異步IO的過(guò)程中會(huì)有異常
nodejs有一個(gè)約定纯陨,將異常作為回調(diào)函數(shù)的第一個(gè)參數(shù)傳回,如果為空值留储,則表明異步調(diào)用沒(méi)有異常拋出队丝,因此寫(xiě)回調(diào)函數(shù)的時(shí)候,首先要判斷其第一個(gè)參數(shù)是否為空欲鹏,再執(zhí)行后面的操作函數(shù)嵌套過(guò)深
阻塞代碼
setTimeout和setInterval不能阻塞后續(xù)代碼的執(zhí)行机久,使用循環(huán)判斷時(shí)間,會(huì)持續(xù)占用CPU進(jìn)行判斷赔嚎,與真正的線程沉睡不同膘盖,完全破壞了事件循環(huán)的調(diào)度,最好使用setTimeout效果更好異步轉(zhuǎn)同步
嵌套回調(diào)尤误,業(yè)務(wù)分散解決方案
觀察者模式