node採用v8引擎來執行,事件迴圈,非同步,雖然是單程式,單執行緒,但是因為非同步,沒有IO的阻塞,效能也不錯
單執行緒缺點:一個執行緒的奔潰,整個程式死掉,優點:開銷小,不影響併發的同資料寫入衝突
應用:webAPI,web應用,多人線上遊戲,通訊
適合:IO高併發,上傳大檔案,前後端分離
傳統web服務:來一個請求,建立一個執行緒,處理過程中還可能需要等待IO,IO阻塞整個執行緒
node:來一個請求,單執行緒去接收進來,後臺有一個IO執行緒池,處理IO讀寫時,這個單執行緒繼續接收下一個請求,但是要清除,一個單執行緒最終不足以抗住大併發,所以還可以做分散式
webstorm的小配置
- 配置run
run(需要配置node的執行bin檔案)setting--language & frameworks -- node.js and npm -- node interpreter -- node.exe路徑
- 開啟node程式碼提示
setting--language & frameworks---node.js and npm---node.js core library is enabled
node的模組
首先我們的js是沒有模組系統的概念的,對於前端來說,本身也沒有業務的概念,僅僅是對瀏覽器的操作和渲染,大多數情況,一些庫,框架,都是基於對js原始碼的封裝,並沒有實際對一個專案的整體規劃和分層(現階段有很大改善了),也沒有一個包管理器;
但此時我們的nodejs是作為後端語言,因此如果還是單純的js開發方式,無疑是不足以承擔起一箇中大型的專案;也就無法對其它後端語言產生任何威脅
因此nodejs引入commonjs規範,做了模組化,加入了npm,以及提供了方便開發者的大量的API;得益於這些東西,和執行機制,使得nodejs在後端語言中,也佔有一席之位;
模組定義
專案中建立的一個js檔案,就是一個模組;
檔案中的內容其實是處於一個函式中,如果想讓外部js使用這個模組中的變數和方法,則需要使用exports匯出
exports.x = 'xxx'
exports.fn = function () {}
模組引用
var name = require('./path/module_name')
name就是該模組物件
其實require()是作為函式的引數傳進來的
底層模組,編譯到node中,不需引入,可直接使用,如Buffer
核心模組,node提供,需引入,var fs = require('fs')
自己寫的模組,需要傳具體的路徑
模組標識
模組標識就是模組的名字,也就是傳遞給require()的引數,它必須是符合駝峰命名法的字串
驗證一下模組檔案中的內容確實是處於一個函式中(區域性)
1. 在node中有一個全域性物件global,它的作用和網頁中的window類似,在全域性中建立的變數,函式會作為global的屬性,方法儲存進去
var a = 100
console.log(global.a) //undefined 不存在全域性中
2. 證明全域性變數會儲存到global中
b = 100;
console.log(global.b) //100
3. 證明模組檔案中的程式碼是存在函式中的
console.log(arguments) 函式的引數
console.log(arguments.callee) 這個屬性儲存的是當前執行的函式物件
console.log(arguments.callee + "");
4. 實際上模組中的程式碼都是包裝在一個函式中執行的,由node引擎呼叫,並且在函式執行時,傳遞進了5個實參
exports 該物件用來將變數或函式暴露到外部
require 函式,用來引入外部的模組
module 代表當前模組本身,exports其實是module的屬性
console.log(exports, module.exports, exports == module.exports)
__filename 當前模組的完整路徑
__dirname 當前模組所在目錄
exports 和 module.exports ?
存的是同一個物件的指標,指向的是同一個物件
這裡先說一下棧和堆:
- 棧記憶體一般存資料量小的,資料結構單一的資料,比如字串,數值,bool,陣列;可以把它看作一個key-value結構,key中存的是變數名稱,value中存的是值;預設都是值傳遞
var a = 10; var b = a; 此時a和b的值都是10;其實是在棧記憶體中,申請了兩個key-value, | key | value | | a | 10 | | b | 10 | a++ | key | value | | a | 11 | | b | 10 |
- 堆記憶體一般存複雜的,大量的資料,比如物件,類,資源,其內部可以看作一個大空間,申請存資料時,劃分一塊空間,同時每塊空間都有一個地址。
一般這些資料都是引用傳值,如下:
var a = {};
var b = a;
| key | value |
| a | 0x123 |
| b | 0x123 |
堆中
| ox123 {} |
a.name = 'xqw';
| ox123 {name:"xqw"} |
a物件的修改,對b一樣起作用,反過來也一樣,因為都是指向的同一個堆空間中
b = {"sex":"men"};
| a | 0x123 |
| b | 0x124 |
| ox123 {name:"xqw"} |
| ox124 {sex:"sex"} |
此時是直接重新賦值b變數了,斷開了原指標,給了一個新指標,此時與a物件沒有關係了;
可以這樣看exports和module.exports
var module = {};
module.exports = {};//module物件,新增了一個exports屬性
var exports = module.exports;//將module.exports的值賦值給exports變數,但是因為module.exports本身是一個物件,因此exports變數中存的是和module.exports相同的指標,即堆物件空間相同;
所以我們匯出時可以這樣:
exports.name = 'xqw'; 等同於 module.exports.name = 'xqw';
exports.fn = ()=>{}; 等同於 module.exports.fn = ()=>{};
其都是對一個物件裡面的元素做調整;
但是假如這樣寫:
exports = {"name":"lyl"}; 這是對變數的值修改,此時exports != module.exports 了,無法匯出了;
我們總是可以使用這種寫法,不會出錯:
module.exports.attr = 'xxx';
module.exports = {...};
exports.xx 是改物件
exports = xx 是改變數
練習:定義一個模組math,在該模組中提供兩個方法,add(a, b) 求和 ; mul(a, b)求積 , index.js中使用這兩個方法 ?
本作品採用《CC 協議》,轉載必須註明作者和本文連結