天天看點

傳統後端開發者視角學習異步Nodejs的血淚筆記

之前一直以傳統後端的思維來寫nodejs的代碼,發現運作結果與我的同步思維方式不太一樣,是以需要全面将nodejs學習一下。此學習筆記适合後端同學學習nodejs的時候觀看,前端大佬可以多多指正。

環境變量

console.log(setTimeout);
console.log(setInterval);
console.log(setImmediate);
console.log(__filename); // 目前檔案的全名
console.log(__dirname); //
console.log(process); // 程序資訊,全局變量      

process就是目前運作環境變量的集合體。例如process.argv就是擷取使用者輸入的參數

數學庫

與Java一樣,叫Math

Math.random(); // 傳回0~1的浮點數      

子產品規範之exports和module.exports的關系

需要解決的問題:

腳本變多時,需要手動管理加載順序 不同腳本之間邏輯調用,需要通過全局變量的方式去交流,例如:JQUERY。将輸出放到全局變量中,然後由其他部分進行使用 沒有html怎麼辦?

nodejs中使用CommonJs子產品規範,加載另一個js,用require函數來擷取即可。

// demo.js
console.log("-----------");
let lib = require('./lib');
console.log('---------',lib);

// lib.js
console.log('==========');
exports.hello = '++++++++++';
exports.word = '///';
exports.add = function () {
    console.log('1111111111111')
};      

可以看見,子產品中定義子產品輸出的方式:預設會注入一個叫export的變量,在該變量上挂參數就相當于給目前被require對象裡面附一個值。還可以挂函數,對象等,理論上就是在輸出對象中加對象。是以在exports中我們可以挂各種類型的結構 同時,對于exports來說,外面可以改變子產品裡面的内容,是同一個引用。

// demo.js
console.log("-----------");
let lib = require('./lib');
lib.addd = '*******************';
console.log('---------',lib);

// lib.js
console.log('==========');
exports.hello = '++++++++++';
exports.word = '///';
exports.add = function () {
    console.log('1111111111111')
};

setTimeout(()=>{
  console.log(exports)
},2000);      

運作結果如下,可以看見修改了外面被require的對象,裡面的exports對象也被修改了

傳統後端開發者視角學習異步Nodejs的血淚筆記

特定地,如果希望被require出來的不是一個對象,而是一個方法,或者變量啥的,可以使用module.exports,但是會覆寫掉之前怼exports變量的修改。

// demo.js
console.log("-----------");
let lib = require('./lib');
console.log('---------',lib);

// lib.js
console.log('==========');
exports.hello = '++++++++++';
exports.word = '///';
exports.add = function () {
    console.log('1111111111111')
};
module.exports = function dsa() {
    return '123'
};      

最終列印的結果為

傳統後端開發者視角學習異步Nodejs的血淚筆記

可以看到結果中exports變量的值并沒有被輸出出來,得到這樣的結果有兩種可能性,第一是module.exports将exports對象給覆寫掉了,第二種是module.exports和exports在檔案被require的時候其實是兩個不同的東西,指向兩個不同的記憶體,當子產品被require的時候,如果module.exports沒有被指定,那麼就require出來的是exports對象,如果module.exports被指定了,那麼就使用module,exports。我比較傾向于後面這種解釋,下面來證明我的觀點。

// demo.js
console.log("-----------");
let lib = require('./lib');
lib.addd = '*******************';
console.log('---------',lib);

// lib.js
console.log('==========');
exports.hello = '++++++++++';
exports.word = '///';
exports.add = function () {
    console.log('1111111111111')
};

setTimeout(()=>{
  console.log(exports)
},2000);

module.exports = function dsa() {
    return '123'
};

setTimeout(()=>{
  console.log(module.exports)
},2000);      

運作結果為:

傳統後端開發者視角學習異步Nodejs的血淚筆記

可以看到,在demo.js中給引用的lib新增了addd屬性,最終是作用到了module.exports上,同時,exports列印的結果與module.exports并不一樣,說明,module.exports和exports不是一個對象,隻是在一個子產品被引用時,module.exports的優先級要高于exports。

擷取控制台輸入(标準輸入輸出)

process.stdin.on('data', (e) => {
    const x = e.toString().trim();
    console.log(x);
} );      

包管理工具

每個語言都有包管理工具,不過nodejs有個坑,就是npm有時候版本和nodejs不比對,這個時候就會抛出一些莫名其妙的錯誤。碰到這種情況,就隻能去​​npm官網解決問題部分​​尋找結果了。

npm init

要使用npm,需要本身就是一個npm目錄,是以需要使用 npm init 來聲明為npm 包

package.json

dependencies:放在裡面,npm install時會被自動下載下傳,聲明目前npm包所有的依賴

安裝解除安裝
npm install xxx
npm uninstall xxx      
國内鏡像

npm是國外的鏡像,可以使用淘寶的npm鏡像,可以去​​NPM鏡像​​檢視相關的方法 值得注意的是,用cnpm的時候要加上--save指令,否則dependencies中不會加進去

npm search xxx

很多同學不知道自己适合用什麼包,比如我想連接配接redis,該使用什麼包呢?就可以使用 npm search redis來尋找了,相同的,docker search redis/composer search redis 等等都是這麼玩的。

nodejs架構

基于V8運作環境 事件驅動:非阻塞式的IO模型

内置子產品

​​nodejs官方網站文檔頁面​​​ ​​nodejs官方網站文檔中文頁面​​

底層能力是怎麼完成的

以os為例,在源碼的lib檔案中:internalBinding('os') 在 src/node_os.cc中再調用v8的能力

Event子產品實作觀察者模式,進而使得兩個對象進行傳輸

EventEmitter,process繼承與它,是以可以往上抛事件,也就是典型的觀察者模式。底層的能力封裝起來放到一個子產品中,外面的子產品拿到這個代碼,通過事件的監聽器,就能比較友善的,知道子子產品裡面發生的變化。 觀察者模式,可以用來解決兩個對象的交流問題。 其實這個方法也可以實作兩個函數的先後執行,進而将代碼過程化,我看到這個還是比較興奮的,這樣我就可以解決本來具有先後執行順序的代碼,由于nodejs的異步特性導緻無法實作的,可以利用這個模式實作

const  EventEmitter = require('events').EventEmitter;

class X extends EventEmitter{
    constructor(){
        super();
        setInterval(()=>{
            this.emit('newlesson',{
                price:Math.random()*100
            });
        },3000)
    }
}

const x = new X();
x.addListener('newlesson',(res)=>{
    console.log('buy!',res);
});      

繼續閱讀