深入淺出nodejs

1.node特點(diǎn)

高性能web服務(wù)器的要點(diǎn):事件驅(qū)動(dòng)、非阻塞I/O

  • 單線(xiàn)程
    單線(xiàn)程的優(yōu)點(diǎn)在于:
    • 不用在意狀態(tài)同步問(wèn)題
    • 沒(méi)有死鎖的存在
    • 沒(méi)有線(xiàn)程上下文交換帶來(lái)的性能上的開(kāi)銷(xiāo)
      單線(xiàn)程的缺點(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)解決單線(xiàn)程中大量計(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ù)集群做了劃分和映射,查詢(xún)調(diào)用依舊是針對(duì)單張表進(jìn)行SQL查詢(xún),中間層分解查詢(xún)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)行了頭尾包裝:
(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)判斷類(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線(xiàn)程相當(dāng)于一個(gè)分配任務(wù)和處理結(jié)果的大管家,IO線(xiàn)程池里的各個(gè)IO線(xiàn)程都是小二,js線(xiàn)程無(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)行判斷,與真正的線(xiàn)程沉睡不同,完全破壞了事件循環(huán)的調(diào)度,最好使用setTimeout效果更好

  • 異步轉(zhuǎn)同步
    嵌套回調(diào),業(yè)務(wù)分散

  • 解決方案
    觀察者模式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容