02、NodeJS-基礎(chǔ)

一愈魏、異步編程

  • 異步操作
  - Node 采用 Chrome V8 引擎處理 JavaScript 腳本觅玻, V8 最大特點就是單線程運行,一次只能運行一個任務(wù)
  - Node 大量采用異步操作(asynchronous operation)培漏,即任務(wù)不是馬上執(zhí)行溪厘,而是插在任務(wù)隊列的尾部,等到前面的任務(wù)運行完后再執(zhí)行
  - 提高代碼的響應(yīng)能力

Node大量采用異步操作牌柄,即任務(wù)不是馬上執(zhí)行畸悬,而是直接插入任務(wù)隊列的尾部,等前面任務(wù)執(zhí)行完成后再只執(zhí)行友鼻。異步執(zhí)行傻昙,而不是單線程執(zhí)行(一次只能執(zhí)行一個任務(wù)),這大大提高代碼的響應(yīng)能力彩扔。
【Node中妆档,所有會發(fā)生阻塞的操作都是異步的〕娴铮】

  - setTimeout()
  - ajax
  - 文件操作
  ...
  • 異步操作回調(diào)
    由于系統(tǒng)永遠(yuǎn)不知道用戶什么時候會輸入內(nèi)容贾惦,所以代 碼不能永遠(yuǎn)停在一個地方;
    Node 中的操作方式就是以異步回調(diào)的方式解決無狀態(tài) 的問題;
  • 回調(diào)函數(shù)的設(shè)計
  - 回調(diào)函數(shù)一定作為參數(shù)的最后一個參數(shù)出現(xiàn):
    function foo1(name, age, callback) { }
    function foo2(value, callback1, callback2) { }

  - 回調(diào)函數(shù)的第一個參數(shù)默認(rèn)接收錯誤信息,第二個參數(shù)才是真正 的回調(diào)數(shù)據(jù)(便于外界獲取調(diào)用的錯誤情況):
     foo1('李明', 19, function(error, data) { 
        if(error) throw error;
          console.log(data);
      });

***錯誤優(yōu)先: ***因為之后的操作大多數(shù)都是異步的方式敦捧,無法通過 try catch 捕獲異常; 所以在node中錯誤優(yōu)先的回調(diào)函數(shù)须板,第一個參數(shù)為上一步的錯誤信息。

回調(diào)函數(shù)的設(shè)計
  • 異步回調(diào)的問題
  - 異步事件驅(qū)動的代碼不容易閱讀
  - 不容易調(diào)試
  - 不容易維護(hù)

二兢卵、進(jìn)程和線程

  • 什么是進(jìn)程
  - 一個正在運行 的應(yīng)用程序都稱之為進(jìn)程;
  - 每一個應(yīng)用程序都至少有一個進(jìn)程;
  - 進(jìn)程是用來給應(yīng)用程序提供一個運行的環(huán)境;
  - 進(jìn)程是操作系統(tǒng)為應(yīng)用程序分配資源的一個單位;
  • 什么是線程
  - 用來執(zhí)行應(yīng)用程序中的代碼;
  - 在一個進(jìn)程內(nèi)部习瑰,可以有很多的線程;
  - 在一個線程內(nèi)部,同時只可以干一件事;
  - 而且傳統(tǒng)的開發(fā)方式大部分都是 I/O 阻塞的;
  - 所以需要多線程來更好的利用硬件資源;
  - 給人帶來一種錯覺:線程越多越好;

多線程同時執(zhí)行秽荤,真實情況并不是"同時"甜奄,因為CPU只有一個柠横;
線程問題: 線程創(chuàng)建需要耗費資源,線程數(shù)量也不能無限添加课兄,線程同步操作牍氛,線程間數(shù)據(jù)共享,CPU中線程間的切換有上下文的轉(zhuǎn)換是需要耗時的....
在node中烟阐,實現(xiàn)異步非阻塞操作搬俊,并不是使用多線程實現(xiàn)了(常規(guī)的異步非阻塞是通過多線程實現(xiàn)的)。*** Node.js在設(shè)計上也是比較大膽蜒茄,它以單進(jìn)程唉擂、單線程模式運行。事件驅(qū)動機制是Node.js通過內(nèi)部單線程高效率地維護(hù)事件循環(huán)隊列來實現(xiàn)的扩淀,沒有多線程的資源占用和上下文切換楔敌,這意味著面對大規(guī)模的http請求,Node.js憑借事件驅(qū)動搞定一切驻谆。***

三卵凑、事件驅(qū)動

事件驅(qū)動是NodeJS中一大特性。事件驅(qū)動胜臊,就是通過監(jiān)聽事件的狀態(tài)變化來作出相應(yīng)的操作勺卢。例如文件存在,文件不存在象对,文件讀取完畢黑忱,文件讀取錯誤,觸發(fā)對應(yīng)的狀態(tài)勒魔,之后通過回調(diào)函數(shù)進(jìn)行處理甫煞。

  • 線程驅(qū)動和事件驅(qū)動
    • 線程驅(qū)動就是當(dāng)收到一個請求的時候,將會為該請求開一個新的線程來處理請求冠绢。一般存在一個線程池抚吠,線程池中有空閑的線程,會從線程池中拿取線程來進(jìn)行處理弟胀,如果線程池中沒有空閑的線程楷力,新來的請求將會進(jìn)入隊列排隊,直到線程池中空閑線程孵户;


      線程驅(qū)動
    • 事件驅(qū)動就是當(dāng)進(jìn)來一個新的請求的時萧朝,請求將會被壓入隊列中,然后通過一個循環(huán)來檢測隊列中的事件狀態(tài)變化夏哭,如果檢測到有狀態(tài)變化的事件检柬,那么就執(zhí)行該事件對應(yīng)的處理代碼,一般都是回調(diào)函數(shù)竖配;

在美國去看醫(yī)生何址,需要填寫大量表格酱固,比如保險、個人信息之類头朱,傳統(tǒng)的基于線程的系統(tǒng)(thread-based system),接待員叫到你龄减,你需要在前臺填寫完成這些表格项钮,你站著填單,而接待員坐著看你填單希停。你讓接待員沒辦法接待下一個客戶烁巫,除非完成你的業(yè)務(wù)。想讓這個系統(tǒng)能運行的快一些宠能,只有多加幾個接待員亚隙,人力成本需要增加不少。

基于事件的系統(tǒng)(event-based system)中违崇,當(dāng)你到窗口發(fā)現(xiàn)需要填寫一些額外的表格而不僅僅是掛個號阿弃,接待員把表格和筆給你,告訴你可以找個座位填寫羞延,填完了以后再回去找他渣淳。你回去坐著填表,而接待員開始接待下一個客戶伴箩。你沒有阻塞接待員的服務(wù)入愧。
你填完表格,返回隊伍中嗤谚,等接待員接待完現(xiàn)在的客戶棺蛛,你把表格遞給他。如果有什么問題或者需要填寫額外的表格巩步,他給你一份新的旁赊,然后重復(fù)這個過程。
這個系統(tǒng)已經(jīng)非常高效了渗钉,幾乎大部分醫(yī)生都是這么做的彤恶。如果等待的人太多,可以加入額外的接待員進(jìn)行服務(wù)鳄橘,但是肯定要比基于線程模式的少得多声离。

事件驅(qū)動1

事件驅(qū)動2

四、模塊化結(jié)構(gòu)

  • 模塊與文件是一一對應(yīng)關(guān)系瘫怜,即加載一個模塊术徊,實際上
    就是加載對應(yīng)的一個模塊文件

  • 模塊的分類

  - 文件模塊
      就是我們自己寫的功能模塊文件
  - 核心模塊
      Node 平臺自帶的一套基本的功能模塊,也有人稱之為 Node平臺的 API
  - 第三方模塊
      社區(qū)或第三方個人開發(fā)好的功能模塊鲸湃,可以直接拿回來用
  • 模塊化開發(fā)的流程
  - new compute.js  創(chuàng)建模塊(一個模塊就一個文件)
  - module.exports = {}  導(dǎo)出成員
  - var comp = require('./compute.js')  載入模塊
  - comp.add(1, 1)  使用模塊

五赠涮、定義模塊

  • 模塊內(nèi)全局環(huán)境
  -  __dirname
      用于獲取當(dāng)前文件所在目錄的完整路徑
      在 REPL 環(huán)境無效
  -  __filename
      用來獲取當(dāng)前文件的完整路徑
      在 REPL 環(huán)境同樣無效
  - module 
      模塊對象
  - exports
      映射到module.exports的別名
  - require()
      require.cache
      require.extensions
      require.main
      require.resolve()

文件操作中必須使用絕對路徑;

  • module 對象
    Node 內(nèi)部提供一個 Module 構(gòu)建函數(shù)子寓。所有模塊都是 Module 的實例;
  – module.id 模塊的識別符笋除,通常是帶有絕對路徑的模塊文件名;
  - module.filename 模塊定義的文件的絕對路徑;
  – module.loaded 返回一個布爾值斜友,表示模塊是否已經(jīng)完成加載;
  – module.parent 返回一個對象,表示調(diào)用該模塊的模塊;
  – module.children 返回一個數(shù)組垃它,表示該模塊要用到的其他模塊;
  – module.exports 表示模塊對外輸出的值;
  • 模塊的定義
  - 一個新的 JS 文件就是一個模塊;
  - 一個合格的模塊應(yīng)該是有導(dǎo)出成員的鲜屏,否則模塊就失去了定義的價值;
  - 模塊內(nèi)部是一個獨立(封閉)的作用域(模塊與模塊之間不會沖突);
  - 模塊之間必須通過導(dǎo)出或?qū)氲姆绞絽f(xié)同;
  - 導(dǎo)出方式
      exports.name = value;
      module.exports = { name: value };
  - module.exports是用于為模塊導(dǎo)出成員的接口;
  - exports是指向module.exports的別名,相當(dāng)于 在模塊開始的時候執(zhí)行
      var exports = module.exports;
  - 一旦為 module.exports 賦值国拇,就會切斷之前兩者的相關(guān)性;
  - 最終模塊的導(dǎo)出成員以 module.exports 為準(zhǔn);

1洛史、每個模塊的內(nèi)部都是私有空間,不會污染全局作用域酱吝;
2也殖、模塊可以多次加載,但是只會在第一次加載時運行一次务热, 然后運行結(jié)果就被緩存了忆嗜,以后再加載,就直接讀取緩 存結(jié)果崎岂;
3霎褐、模塊加載的順序,按照其在代碼中出現(xiàn)的順序该镣;

六冻璃、載入模塊

  • require是什么
    require 的基本功能是,讀入并執(zhí)行一個JavaScript文件损合,然后返回該模塊的exports對象;

  • require擴展名
    require 加載文件時可以省略擴展名;

  require('./module');
  
  // 1省艳、此時文件按 JS 文件執(zhí)行
  require('./module.js');
  // 2、此時文件按 JSON 文件解析
  require('./module.json');
  // 3嫁审、此時文件預(yù)編譯好的 C++ 模塊執(zhí)行
  require('./module.node');
  • require加載文件規(guī)則
  - 通過 ./ 或 ../ 開頭:則按照相對路徑從當(dāng)前文件所在文件夾開始尋找模塊
      require('../file.js');   // 上級目錄下找 file.js 文件
  - 通過 / 開頭:則以系統(tǒng)根目錄開始尋找模塊
      require('/Users/zyz/Documents/file.js');  // 以絕對路徑的方式找
  - 如果參數(shù)字符串不以“./“ 或 ”/“ 開頭跋炕,則表示加載 的是一個默認(rèn)提供的核心模塊(位于 Node 的系統(tǒng)安 裝目錄中)
      require('fs');   // 加載核心模塊中的文件系統(tǒng)模塊
  - 或者從當(dāng)前目錄向上搜索 node_modules 目錄中的文件
      require('my_module'); // 各級 node_modules文件夾中搜索 my_module.js 文件;

require('my_module'); 開始是在核心模塊中查找,這個其實不是核心模塊律适;接著各級 node_modules文件夾中搜索

  • 模塊的緩存
    • 第一次加載某個模塊時辐烂,Node會緩存該模塊。以后再 加載該模塊捂贿,就直接從緩存取出該模塊的 module.exports 屬性(不會再次執(zhí)行該模塊)
    • 模塊的緩存可以通過require.cache拿到纠修,同樣也可以刪除
    //  模塊的緩存的刪除
    Object.keys(require.cache).forEach( (key) => {
        delete require.cache[key];
    } );
  • 如果需要多次執(zhí)行模塊中的代碼,一般可以讓模塊暴露行為(函數(shù))【避免每次都要清理緩存的問題】
  // 緩存的問題 -- 方式1
  module.exports = () => {
      return {time: new Date()};
  }
  // 緩存的問題 -- 方式2
    function fn(){
        return {time: new Date()};
     }
    module.exports = {fn};
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末厂僧,一起剝皮案震驚了整個濱河市扣草,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖辰妙,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鹰祸,死亡現(xiàn)場離奇詭異,居然都是意外死亡密浑,警方通過查閱死者的電腦和手機蛙婴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來尔破,“玉大人敬锐,你說我怎么就攤上這事〈粽埃” “怎么了?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵径玖,是天一觀的道長痴脾。 經(jīng)常有香客問我,道長梳星,這世上最難降的妖魔是什么赞赖? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮冤灾,結(jié)果婚禮上前域,老公的妹妹穿的比我還像新娘。我一直安慰自己韵吨,他們只是感情好匿垄,可當(dāng)我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著归粉,像睡著了一般椿疗。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上糠悼,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天届榄,我揣著相機與錄音,去河邊找鬼倔喂。 笑死铝条,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的席噩。 我是一名探鬼主播班缰,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼悼枢!你這毒婦竟也來了鲁捏?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎给梅,沒想到半個月后假丧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡动羽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年包帚,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片运吓。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡渴邦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拘哨,到底是詐尸還是另有隱情谋梭,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布倦青,位于F島的核電站瓮床,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏产镐。R本人自食惡果不足惜隘庄,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望癣亚。 院中可真熱鬧丑掺,春花似錦、人聲如沸述雾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽玻孟。三九已至菇肃,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間取募,已是汗流浹背琐谤。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留玩敏,地道東北人斗忌。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像旺聚,于是被迫代替她去往敵國和親织阳。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,619評論 2 354

推薦閱讀更多精彩內(nèi)容

  • topics: 1.The Node.js philosophy 2.The reactor pattern 3....
    宮若石閱讀 1,078評論 0 1
  • Node.js是目前非撑榇猓火熱的技術(shù)唧躲,但是它的誕生經(jīng)歷卻很奇特。 眾所周知,在Netscape設(shè)計出JavaScri...
    w_zhuan閱讀 3,613評論 2 41
  • 模塊 Node 有簡單的模塊加載系統(tǒng)弄痹。在 Node 里饭入,文件和模塊是一一對應(yīng)的。下面例子里肛真,foo.js加載同一個...
    保川閱讀 596評論 0 0
  • Node.js是目前非承扯火熱的技術(shù),但是它的誕生經(jīng)歷卻很奇特蚓让。 眾所周知乾忱,在Netscape設(shè)計出JavaScri...
    Myselfyan閱讀 4,071評論 2 58
  • 素日里,我像只在黑夜偷生的蟑螂一樣历极,爬行在杯盤中尋找別人牙縫里遺漏的殘羹冷炙窄瘟,津津有味的品嘗著物質(zhì)給我?guī)淼哪嵌?..
    竹鴻初閱讀 185評論 0 0