node.js學(xué)習(xí)筆記二

V8最大的特點(diǎn)就是單線程,一次只能運(yùn)行一個(gè)任務(wù)

node存在大量異步操作

在異步操作中侦副,無法通過try...catch...捕獲異常

異步回調(diào)相比傳統(tǒng)代碼:

采用異步事件驅(qū)動(dòng)

不容易閱讀

不容易調(diào)試

不容易維護(hù)

什么是進(jìn)程?

每一個(gè)正在運(yùn)行的程序都可稱之為進(jìn)程

每一個(gè)應(yīng)用程序至少有一個(gè)進(jìn)程

多線程

如果是多線程:

node進(jìn)程啟動(dòng)后會(huì)默認(rèn)創(chuàng)建一個(gè)線程(主線程),用于執(zhí)行代碼没咙, 對(duì)于比較花費(fèi)

時(shí)間的操作,再給它創(chuàng)建一個(gè)線程去執(zhí)行千劈。主線程往 下走祭刚,碰到比較耗時(shí)的操作,再給這端代碼創(chuàng)建一個(gè)線程去執(zhí)行...

那么問題來了墙牌,線程越多越好嗎涡驮?

答案是否定的

----多線程帶來的問題:

--線程之間共享某些數(shù)據(jù),同步某個(gè)狀態(tài)都很麻煩

--創(chuàng)建線程花費(fèi)時(shí)間

--能夠創(chuàng)建的線程數(shù)量有限

--CPU切換線程時(shí)要切換上下文喜滨,非常耗時(shí)

node單線程執(zhí)行過程:

node內(nèi)部有一個(gè)事件隊(duì)列捉捅,當(dāng)碰到耗時(shí)操作比如文件操作,將該事件加入事件隊(duì)列虽风,主線程往下執(zhí)行锯梁,又碰到耗時(shí)操作,再往事件隊(duì)列中加入該事件焰情,以此類推陌凳,

主線程執(zhí)行完下面的代碼(主線程空閑),去執(zhí)行事件隊(duì)列中的代碼操作内舟,執(zhí)行完之后合敦,執(zhí)行它的回調(diào),回調(diào)完成验游,執(zhí)行跟它的回調(diào)相關(guān)的代碼操作(如果有)充岛,如果這個(gè)操作是耗時(shí)的比如文件操作(如果是不耗時(shí)的,即非阻塞的耕蝉,則不用交出去崔梗,直接自己執(zhí)行了就好),將該操作加入事件隊(duì)列垒在,主線程空閑時(shí)蒜魄,執(zhí)行后來的這個(gè)事件隊(duì)列中的事件,執(zhí)行完該事件场躯,執(zhí)行它的回調(diào)...

對(duì)于事件隊(duì)列谈为,不管是主線程開始碰到的事件還是回調(diào)函數(shù)中的事件,都是執(zhí)行到

(碰到)這部分代碼的時(shí)候踢关,將其加入事件隊(duì)列的隊(duì)尾伞鲫,而事件隊(duì)列中的事件的執(zhí)行順序是按照隊(duì)列的順序執(zhí)行的

注意,本質(zhì)上node程序的處理還是多線程的签舞,node主線程負(fù)責(zé)處理源程序事件隊(duì)

列中的非阻塞的操作秕脓,而阻塞的操作柒瓣,則交給線程池中的線程去處理,線程池中的

線程幫助處理完這個(gè)事件吠架,利用回調(diào)函數(shù)將結(jié)果送給主線程芙贫。總之诵肛,node本身主

線程主要做調(diào)度工作(和非阻塞操作)屹培。

線程池中有一些已經(jīng)創(chuàng)建好的線程默穴,供node主線程調(diào)用

非阻塞的好處:

--提高代碼響應(yīng)效率

--充分利用單核CPU的優(yōu)勢(shì)

--改善I/O的不可預(yù)測帶來的問題

但是目前市面上大多是多核CPU怔檩,大多通過硬件虛擬化將多核虛擬成單核

在node中,啟用嚴(yán)格模式‘use strict’

V8對(duì)ES6支持情況分為三種情況:不支持蓄诽、直接支持薛训、嚴(yán)格模式下支持

比如let 就需要啟用嚴(yán)格模式,或者用其他方式做些轉(zhuǎn)換

chrome瀏覽器在打開網(wǎng)頁請(qǐng)求的時(shí)候仑氛,會(huì)自動(dòng)請(qǐng)求項(xiàng)目根目錄下面的favicon.ico

圖標(biāo)

node采用CommonJS規(guī)范乙埃,模塊和文件是一一對(duì)應(yīng)關(guān)系,加載一個(gè)模塊锯岖,實(shí)際上就是加載對(duì)應(yīng)的一個(gè)模塊文件介袜。

CommonJS

CommonJS API定義很多普通應(yīng)用程序(主要指非瀏覽器的應(yīng)用)使用的API,從

而填補(bǔ)了這個(gè)空白出吹。它的終極目標(biāo)是提供一個(gè)類似Python遇伞,Ruby和Java標(biāo) 準(zhǔn)庫。

這樣的話捶牢,開發(fā)者可以使用CommonJS API編寫應(yīng)用程序鸠珠,然后這些應(yīng)用可以運(yùn)行

在不同的JavaScript解釋器和不同的主機(jī)環(huán)境中。

在兼容CommonJS的系統(tǒng)中秋麸,你可以使用 JavaScript程序開發(fā):

--服務(wù)器端JavaScript應(yīng)用程序

--命令行工具

--圖形界面應(yīng)用程序

--混合應(yīng)用程序(如渐排,Titanium或Adobe AIR)

Node.js采用了這個(gè)規(guī)范,根據(jù)CommonJS規(guī)范灸蟆,一個(gè)單獨(dú)的文件就是一個(gè)模塊驯耻。

加載模塊使用require方法,該方法讀取一個(gè)文件并執(zhí)行炒考,最后返回文件內(nèi)部的

exports對(duì)象吓歇。

//sum.js
 exports.sum = function(){...做加操作..};
 
 //calculate.js
 var math = require('sum');
exports.add = function(n){
    return math.sum(val,n);
 };

--------------------

ES6中箭頭函數(shù)與普通函數(shù)this的區(qū)別

普通函數(shù)中的this:

  1. this總是代表它的直接調(diào)用者, 例如 obj.func ,那么func中的this就是obj

2.在默認(rèn)情況(非嚴(yán)格模式下,未使用 'use strict'),沒找到直接調(diào)用者,則this指的是 window

3.在嚴(yán)格模式下,沒有直接調(diào)用者的函數(shù)中的this是 undefined

4.使用call,apply,bind(ES5新增)綁定的,this指的是 綁定的對(duì)象

箭頭函數(shù)中的this

默認(rèn)指向在定義它時(shí),它所處的對(duì)象,而不是執(zhí)行時(shí)的對(duì)象, 定義它的時(shí)候,可能環(huán)境是

window(即繼承父級(jí)的this);


模塊的分類

----文件模塊,就是我們自己寫的功能模塊文件

自定義模塊開發(fā)流程:

創(chuàng)建模塊--------new calc.js(新建一個(gè)calc.js文件)

導(dǎo)出模塊--------module.exports = {}

載入模塊--------const calc = require('./calc.js')

使用模塊--------calc.add(1, 2)

----核心模塊票腰,Node平臺(tái)自帶的一套基本功能模塊城看,也稱為Node平臺(tái)的API

----第三方模塊,社區(qū)或第三方個(gè)人開發(fā)好的功能模塊杏慰,可以直接拿來用

模塊中的全局成員

__dirname 獲取當(dāng)前腳本所在目錄路徑

__filename 獲取當(dāng)前腳本文件所在目錄路徑

console.log(__dirname);

console.log(__filename);

輸出:
F:\fore-end\materials\Node.js\projs\proj2
F:\fore-end\materials\Node.js\projs\proj2\test.js

如果想要在test.js中讀取上一個(gè)目錄中的content.txt文件

const fs = require('fs');
//所有的文件操作路徑都應(yīng)該是絕對(duì)路徑(物理路徑)
fs.readFile(dirname + '/../content.txt', (error, content) => {
    if (error) throw error;
    
    console.log(content.toString());
});

每個(gè)模塊內(nèi)部都是私有空間

//test.js

const fs = require('./error.js')

console.log(a);

//error.js

let a;

//執(zhí)行結(jié)果:

a is not defined

模塊內(nèi)部是一個(gè)獨(dú)立的作用域测柠,所以模塊內(nèi)部變量和方法不會(huì)污染全局炼鞠,而在客戶

端通過script標(biāo)簽引入JS文件,那么他們具有相同的作用域

node有一個(gè)module對(duì)象轰胁,我們打印一下這個(gè)對(duì)象

//test.js

const fs = require('./error.js')

module.exports = {
    print: () => (console.log(1))
}

console.log(mudole);

//error.js

let a;

//執(zhí)行test.js打印module對(duì)象

Module {
  id: '.',
  exports: { print: [Function: print] },
  parent: null,
  filename: 'F:\\fore-end\\materials\\Node.js\\projs\\proj2\\test.js',
  loaded: false,
  children:
   [ Module {
       id: 'F:\\fore-end\\materials\\Node.js\\projs\\proj2\\error.js',
       exports: {},
       parent: [Circular],
       filename: 'F:\\fore-end\\materials\\Node.js\\projs\\proj2\\error.js',
       loaded: true,
       children: [],
       paths: [Object] } ],
  paths:
   [ 'F:\\fore-end\\materials\\Node.js\\projs\\proj2\\node_modules',
     'F:\\fore-end\\materials\\Node.js\\projs\\node_modules',
     'F:\\fore-end\\materials\\Node.js\\node_modules',
     'F:\\fore-end\\materials\\node_modules',
     'F:\\fore-end\\node_modules',
     'F:\\node_modules' ] }

當(dāng)每個(gè)js文件在執(zhí)行或被require的時(shí)候谒主,NodeJS其實(shí)創(chuàng)建了一個(gè)新的實(shí)例var module = new Module(),這個(gè)實(shí)例名叫module赃阀。

可以發(fā)現(xiàn)module對(duì)象有一個(gè)id屬性霎肯,表示這個(gè)module是哪個(gè)module,點(diǎn).表示當(dāng)前modulo

parent和children屬性用來表示當(dāng)前module的parent和children模塊是哪個(gè)模塊

看到module對(duì)象還封裝了一個(gè)exports對(duì)象榛斯,初始值是個(gè)空對(duì)象观游,module.export

其實(shí)是給Module實(shí)例中的exports對(duì)象中添加方法/屬性。

exports對(duì)象

通常使用exports的時(shí)候驮俗,是這么用的:

exports.print = function(){console.log(12345)}
假設(shè)我有一個(gè)JS文件內(nèi)容如下:

console.log(module); //你會(huì)看到Module中的exports為空對(duì)象{}
console.log(exports); //你會(huì)看到Module中的exports為空對(duì)象{}
module.exports = {
  print : function(){console.log(12345)}
}
console.log(module); //你會(huì)看到Module中的exports對(duì)象有了print()方法
exports.name = '小白妹妹';
console.log(module); //你會(huì)看到Module中的exports對(duì)象不僅有了print()方法懂缕,

還有了name屬性
由此也能看出,傳說中的exports其實(shí)是module.exports的引用王凑,你可以這么理解搪柑,NodeJS在你的代碼之前悄悄的加了以下代碼:

var module = new Module();
var exports = module.exports;

exports是module.exports的引用的意思就是兩者指向同一個(gè)對(duì)象,當(dāng)然也可以改變exports的指向索烹,是她不再和module.exports指向同一個(gè)對(duì)象工碾。

改變/設(shè)置對(duì)象的指向方法是module.exports = {對(duì)象} | exports = {對(duì)象},只要發(fā)

生了這個(gè)操作百姓,就確定了指向哪個(gè)對(duì)象渊额。當(dāng)然,module.exports.屬性/方法 |

exports.屬性/方法瓣戚,這樣子添加屬性或方法并不會(huì)改變指向端圈。

你可以這樣:

module.exports.name = 'hello';
exports.age = 10;
module.exports.print = function(){console.log(12345)};

如果只是使用.來添加屬性和方法,module.exports和exports混用是完全可以的.

也可以這樣:

module.exports = {
name : 'hello'
};
exports.age = 10;
module.exports.print = function(){console.log(12345)};

但不可以這樣:

module.exports = {
name : 'hello'
};
exports = {age:10}; // exports現(xiàn)在是{age:10}這個(gè)對(duì)象的引用子库,不再是

module.exports的引用了
console.log(module); //你會(huì)看到Module的exports中只有name屬性2杖ā!仑嗅!

也不可以這樣:

exports.age = 10; 
console.log(module); //你會(huì)看到Module的exports中多了age屬性
module.exports = {
name : 'hello'
};
console.log(module); 

//執(zhí)行結(jié)果

Module {
  id: '.',
  exports: { age: 10 },
  parent: null,
  filename: 'F:\\fore-end\\materials\\Node.js\\projs\\proj2\\test.js',
  loaded: false,
  children: [],
  paths:
   [ 'F:\\fore-end\\materials\\Node.js\\projs\\proj2\\node_modules',
     'F:\\fore-end\\materials\\Node.js\\projs\\node_modules',
     'F:\\fore-end\\materials\\Node.js\\node_modules',
     'F:\\fore-end\\materials\\node_modules',
     'F:\\fore-end\\node_modules',
     'F:\\node_modules' ] }
Module {
  id: '.',
  exports: { name: 'hello' },
  parent: null,
  filename: 'F:\\fore-end\\materials\\Node.js\\projs\\proj2\\test.js',
  loaded: false,
  children: [],
  paths:
   [ 'F:\\fore-end\\materials\\Node.js\\projs\\proj2\\node_modules',
     'F:\\fore-end\\materials\\Node.js\\projs\\node_modules',
     'F:\\fore-end\\materials\\Node.js\\node_modules',
     'F:\\fore-end\\materials\\node_modules',
     'F:\\fore-end\\node_modules',
     'F:\\node_modules' ] }

現(xiàn)在就很明白了宴倍,改變exports的指向后所添加的exports.xxx都是無效的。因?yàn)?/p>

require返回的只會(huì)是module.exports仓技。

require使用規(guī)則

require加載文件可以省略擴(kuò)展名

require不僅僅可以載入JS模塊鸵贬,也可以載入JSON對(duì)象(JSON文件,大部分用于讀取配置信息)

----require的參數(shù)如果不以“./”或“/”開頭脖捻,則表示加載的是一個(gè)默認(rèn)的核心模塊阔逼,比如require('fs')加載核心模塊中的文件系統(tǒng)模塊

一旦出現(xiàn)模塊名重復(fù),系統(tǒng)模塊的優(yōu)先級(jí)最高

自己寫的模塊只要放在node_modules文件夾下地沮,就可以像node自己的核心模塊一樣嗜浮,require不用寫路徑羡亩,直接寫模塊名來加載

模塊的緩存

第一次加載某個(gè)模塊的時(shí)候,node會(huì)緩存該模塊危融,以后再加載該模塊畏铆,就直接從

緩存取出該模塊的module.exports屬性

cache對(duì)象

cache對(duì)象里面有node執(zhí)行后的所有緩存

刪除緩存

Object.keys(require.cache).forEach((key) =>{
    delete require.cache[key];
} )

當(dāng)然,一般我們不需要手動(dòng)清空node的緩存吉殃。

如果我們不去手動(dòng)刪除緩存辞居,又想每次require加載模塊都執(zhí)行模塊中的代碼,比如

下面這種

//time.js

console.log('模塊的的代碼')蛋勺;

module.exports = new Date();

//index.js

setInterval(() => {
    let date = require('./time.js');
    console.log(date.getTime());
}, 1000);

因?yàn)閚ode的緩存瓦灶,第一次載入模塊,執(zhí)行了time.js中的代碼迫卢,而接下來執(zhí)行載入

模塊的時(shí)候倚搬,不會(huì)真的去調(diào)用time.js文件冶共,而是從緩存中調(diào)入緩存的該模塊(其實(shí)

是該模塊上次執(zhí)行結(jié)果的緩存)

執(zhí)行結(jié)果

模塊的的代碼
1512556841717
//第一次執(zhí)行結(jié)束乾蛤,打印了‘模塊的的代碼’,創(chuàng)建了一個(gè)Date對(duì)象捅僵,并將這些結(jié)

果存入緩存
1512556841717
1512556841717
1512556841717
1512556841717
1512556841717
1512556841717
...

我們?cè)撊绾翁幚磉@個(gè)問題呢家卖?

很簡單,反正都是沖緩存中取出這個(gè)模塊庙楚,如果緩存的是一個(gè)方法上荡,那么每次從緩

沖中取出的都是這個(gè)方法,取出方法之后都去執(zhí)行一下馒闷,不就是每次都重新執(zhí)行了

一下方法中的代碼嗎酪捡,所以將我們的代碼放在一個(gè)方法中并導(dǎo)出,修改如下

//time.js

module.exports = () => {
    console.log('模塊的的代碼');
    return new Date();//這個(gè)方法返回一個(gè)Date對(duì)象
}

//index.js

setInterval(() => {
    let date = require('./error.js');
    console.log(date().getTime());//date是個(gè)函數(shù)纳账,執(zhí)行一下逛薇,返回Date

對(duì)象
}, 1000);

執(zhí)行結(jié)果

模塊的的代碼
1512557968297
模塊的的代碼
1512557969303
模塊的的代碼
1512557970304
模塊的的代碼
1512557971306
模塊的的代碼
1512557972308
模塊的的代碼
1512557973310
...
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市疏虫,隨后出現(xiàn)的幾起案子永罚,更是在濱河造成了極大的恐慌,老刑警劉巖卧秘,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件呢袱,死亡現(xiàn)場離奇詭異,居然都是意外死亡翅敌,警方通過查閱死者的電腦和手機(jī)羞福,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蚯涮,“玉大人治专,你說我怎么就攤上這事焊唬。” “怎么了看靠?”我有些...
    開封第一講書人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵赶促,是天一觀的道長。 經(jīng)常有香客問我挟炬,道長鸥滨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任谤祖,我火速辦了婚禮婿滓,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘粥喜。我一直安慰自己凸主,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開白布额湘。 她就那樣靜靜地躺著卿吐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪锋华。 梳的紋絲不亂的頭發(fā)上嗡官,一...
    開封第一講書人閱讀 52,475評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音毯焕,去河邊找鬼衍腥。 笑死,一個(gè)胖子當(dāng)著我的面吹牛纳猫,可吹牛的內(nèi)容都是我干的婆咸。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼芜辕,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼尚骄!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起物遇,我...
    開封第一講書人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤乖仇,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后询兴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體乃沙,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年诗舰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了警儒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蜀铲,靈堂內(nèi)的尸體忽然破棺而出边琉,到底是詐尸還是另有隱情,我是刑警寧澤记劝,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布变姨,位于F島的核電站,受9級(jí)特大地震影響厌丑,放射性物質(zhì)發(fā)生泄漏定欧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一怒竿、第九天 我趴在偏房一處隱蔽的房頂上張望砍鸠。 院中可真熱鬧,春花似錦耕驰、人聲如沸爷辱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽饭弓。三九已至,卻和暖如春厚骗,著一層夾襖步出監(jiān)牢的瞬間示启,已是汗流浹背兢哭。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來泰國打工领舰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人迟螺。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓冲秽,卻偏偏與公主長得像,于是被迫代替她去往敵國和親矩父。 傳聞我的和親對(duì)象是個(gè)殘疾皇子锉桑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

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

  • topics: 1.The Node.js philosophy 2.The reactor pattern 3....
    宮若石閱讀 1,092評(píng)論 0 1
  • Node.js是目前非常火熱的技術(shù)窍株,但是它的誕生經(jīng)歷卻很奇特民轴。 眾所周知,在Netscape設(shè)計(jì)出JavaScri...
    w_zhuan閱讀 3,617評(píng)論 2 41
  • 1 Node.js模塊的實(shí)現(xiàn) 之前在網(wǎng)上查閱了許多介紹Node.js的文章,可惜對(duì)于Node.js的模塊機(jī)制大都著...
    zlx_2017閱讀 1,249評(píng)論 0 1
  • 1 Node.js模塊的實(shí)現(xiàn)# 之前在網(wǎng)上查閱了許多介紹Node.js的文章,可惜對(duì)于Node.js的模塊機(jī)制大都...
    七寸知架構(gòu)閱讀 2,064評(píng)論 1 50
  • Node.js是目前非城蚨火熱的技術(shù)后裸,但是它的誕生經(jīng)歷卻很奇特。 眾所周知冒滩,在Netscape設(shè)計(jì)出JavaScri...
    Myselfyan閱讀 4,076評(píng)論 2 58