01小白學nodejs

junwind發表於2021-05-25

node採用v8引擎來執行,事件迴圈,非同步,雖然是單程式,單執行緒,但是因為非同步,沒有IO的阻塞,效能也不錯
單執行緒缺點:一個執行緒的奔潰,整個程式死掉,優點:開銷小,不影響併發的同資料寫入衝突
應用:webAPI,web應用,多人線上遊戲,通訊
適合:IO高併發,上傳大檔案,前後端分離

傳統web服務:來一個請求,建立一個執行緒,處理過程中還可能需要等待IO,IO阻塞整個執行緒
node:來一個請求,單執行緒去接收進來,後臺有一個IO執行緒池,處理IO讀寫時,這個單執行緒繼續接收下一個請求,但是要清除,一個單執行緒最終不足以抗住大併發,所以還可以做分散式

webstorm的小配置

  1. 配置run
    run(需要配置node的執行bin檔案)setting--language & frameworks -- node.js and npm -- node interpreter -- node.exe路徑
  2. 開啟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 協議》,轉載必須註明作者和本文連結
六月的風

相關文章