NodeJS有難度的面試題,你能答對幾個?

一、Node模塊機制

1.1 請介紹一下node裏的模塊是什麼

Node中,每一個文件模塊都是一個對象,它的定義以下:前端

function Module(id, parent) {
  this.id = id;
  this.exports = {};
  this.parent = parent;
  this.filename = null;
  this.loaded = false;
  this.children = [];
}

module.exports = Module;

var module = new Module(filename, parent);
複製代碼

全部的模塊都是 Module 的實例。能夠看到,當前模塊(module.js)也是 Module 的一個實例。java

1.2 請介紹一下require的模塊加載機制

這道題基本上就能夠了解到面試者對Node模塊機制的瞭解程度 基本上面試提到node

  • 一、先計算模塊路徑
  • 二、若是模塊在緩存裏面,取出緩存
  • 三、加載模塊
  • 四、的輸出模塊的exports屬性便可
// require 其實內部調用 Module._load 方法
Module._load = function(request, parent, isMain) {
  //  計算絕對路徑
  var filename = Module._resolveFilename(request, parent);

  //  第一步:若是有緩存,取出緩存
  var cachedModule = Module._cache[filename];
  if (cachedModule) {
    return cachedModule.exports;

  // 第二步:是否爲內置模塊
  if (NativeModule.exists(filename)) {
    return NativeModule.require(filename);
  }
  
  /********************************這裏注意了**************************/
  // 第三步:生成模塊實例,存入緩存
  // 這裏的Module就是咱們上面的1.1定義的Module
  var module = new Module(filename, parent);
  Module._cache[filename] = module;

  /********************************這裏注意了**************************/
  // 第四步:加載模塊
  // 下面的module.load其實是Module原型上有一個方法叫Module.prototype.load
  try {
    module.load(filename);
    hadException = false;
  } finally {
    if (hadException) {
      delete Module._cache[filename];
    }
  }

  // 第五步:輸出模塊的exports屬性
  return module.exports;
};
複製代碼

接着上一題繼續發問mysql

1.3 加載模塊時,爲何每一個模塊都有__dirname,__filename屬性呢,new Module的時候咱們看到1.1部分沒有這兩個屬性的,那麼這兩個屬性是從哪裏來的

// 上面(1.2部分)的第四步module.load(filename)
// 這一步,module模塊至關於被包裝了,包裝形式以下
// 加載js模塊,至關於下面的代碼(加載node模塊和json模塊邏輯不同)
(function (exports, require, module, __filename, __dirname) {
  // 模塊源碼
  // 假如模塊代碼以下
  var math = require('math');
  exports.area = function(radius){
      return Math.PI * radius * radius
  }
});

複製代碼

也就是說,每一個module裏面都會傳入__filename, __dirname參數,這兩個參數並非module自己就有的,是外界傳入的linux

1.4 咱們知道node導出模塊有兩種方式,一種是exports.xxx=xxx和Module.exports={}有什麼區別嗎

  • exports其實就是module.exports
  • 其實1.3問題的代碼已經說明問題了,接着我引用廖雪峯大神的講解,但願能講的更清楚
module.exports vs exports
不少時候,你會看到,在Node環境中,有兩種方法能夠在一個模塊中輸出變量:

方法一:對module.exports賦值:

// hello.js

function hello() {
    console.log('Hello, world!');
}

function greet(name) {
    console.log('Hello, ' + name + '!');
}

module.exports = {
    hello: hello,
    greet: greet
};
方法二:直接使用exports:

// hello.js

function hello() {
    console.log('Hello, world!');
}

function greet(name) {
    console.log('Hello, ' + name + '!');
}

function hello() {
    console.log('Hello, world!');
}

exports.hello = hello;
exports.greet = greet;
可是你不能夠直接對exports賦值:

// 代碼能夠執行,可是模塊並無輸出任何變量:
exports = {
    hello: hello,
    greet: greet
};
若是你對上面的寫法感到十分困惑,不要着急,咱們來分析Node的加載機制:

首先,Node會把整個待加載的hello.js文件放入一個包裝函數load中執行。在執行這個load()函數前,Node準備好了module變量:

var module = {
    id: 'hello',
    exports: {}
};
load()函數最終返回module.exports:

var load = function (exports, module) {
    // hello.js的文件內容
    ...
    // load函數返回:
    return module.exports;
};

var exportes = load(module.exports, module);
也就是說,默認狀況下,Node準備的exports變量和module.exports變量其實是同一個變量,而且初始化爲空對象{},因而,咱們能夠寫:

exports.foo = function () { return 'foo'; };
exports.bar = function () { return 'bar'; };
也能夠寫:

module.exports.foo = function () { return 'foo'; };
module.exports.bar = function () { return 'bar'; };
換句話說,Node默認給你準備了一個空對象{},這樣你能夠直接往裏面加東西。

可是,若是咱們要輸出的是一個函數或數組,那麼,只能給module.exports賦值:

module.exports = function () { return 'foo'; };
給exports賦值是無效的,由於賦值後,module.exports仍然是空對象{}。

結論
若是要輸出一個鍵值對象{},能夠利用exports這個已存在的空對象{},並繼續在上面添加新的鍵值;

若是要輸出一個函數或數組,必須直接對module.exports對象賦值。

因此咱們能夠得出結論:直接對module.exports賦值,能夠應對任何狀況:

module.exports = {
    foo: function () { return 'foo'; }
};
或者:

module.exports = function () { return 'foo'; };
最終,咱們強烈建議使用module.exports = xxx的方式來輸出模塊變量,這樣,你只須要記憶一種方法。
複製代碼

二、Node的異步I/O

本章的答題思路大多借鑑於樸靈大神的《深刻淺出的NodeJS》web

2.1 請介紹一下Node事件循環的流程

  • 在進程啓動時,Node便會建立一個相似於while(true)的循環,每執行一次循環體的過程咱們成爲Tick。面試

  • 每一個Tick的過程就是查看是否有事件待處理。若是有就取出事件及其相關的回調函數。而後進入下一個循環,若是再也不有事件處理,就退出進程。算法

2.2 在每一個tick的過程當中,如何判斷是否有事件須要處理呢?

  • 每一個事件循環中有一個或者多個觀察者,而判斷是否有事件須要處理的過程就是向這些觀察者詢問是否有要處理的事件。sql

  • 在Node中,事件主要來源於網絡請求、文件的I/O等,這些事件對應的觀察者有文件I/O觀察者,網絡I/O的觀察者。數據庫

  • 事件循環是一個典型的生產者/消費者模型。異步I/O,網絡請求等則是事件的生產者,源源不斷爲Node提供不一樣類型的事件,這些事件被傳遞到對應的觀察者那裏,事件循環則從觀察者那裏取出事件並處理。

  • 在windows下,這個循環基於IOCP建立,在*nix下則基於多線程建立

2.3 請描述一下整個異步I/O的流程

三、V8的垃圾回收機制

3.1 如何查看V8的內存使用狀況

使用process.memoryUsage(),返回以下

{
  rss: 4935680,
  heapTotal: 1826816,
  heapUsed: 650472,
  external: 49879
}
複製代碼

heapTotalheapUsed 表明V8的內存使用狀況。 external表明V8管理的,綁定到Javascript的C++對象的內存使用狀況。 rss, 駐留集大小, 是給這個進程分配了多少物理內存(佔總分配內存的一部分) 這些物理內存中包含堆,棧,和代碼段。

3.2 V8的內存限制是多少,爲何V8這樣設計

64位系統下是1.4GB, 32位系統下是0.7GB。由於1.5GB的垃圾回收堆內存,V8須要花費50毫秒以上,作一次非增量式的垃圾回收甚至要1秒以上。這是垃圾回收中引發Javascript線程暫停執行的事件,在這樣的花銷下,應用的性能和影響力都會直線降低。

3.3 V8的內存分代和回收算法請簡單講一講

在V8中,主要將內存分爲新生代和老生代兩代。新生代中的對象存活時間較短的對象,老生代中的對象存活時間較長,或常駐內存的對象。

3.3.1 新生代

新生代中的對象主要經過Scavenge算法進行垃圾回收。這是一種採用複製的方式實現的垃圾回收算法。它將堆內存一份爲二,每一部分空間成爲semispace。在這兩個semispace空間中,只有一個處於使用中,另外一個處於閒置狀態。處於使用狀態的semispace空間稱爲From空間,處於閒置狀態的空間稱爲To空間。

  • 當開始垃圾回收的時候,會檢查From空間中的存活對象,這些存活對象將被複制到To空間中,而非存活對象佔用的空間將會被釋放。完成複製後,From空間和To空間發生角色對換。

  • 應爲新生代中對象的生命週期比較短,就比較適合這個算法。

  • 當一個對象通過屢次複製依然存活,它將會被認爲是生命週期較長的對象。這種新生代中生命週期較長的對象隨後會被移到老生代中。

3.3.2 老生代

老生代主要採起的是標記清除的垃圾回收算法。與Scavenge複製活着的對象不一樣,標記清除算法在標記階段遍歷堆中的全部對象,並標記活着的對象,只清理死亡對象。活對象在新生代中只佔叫小部分,死對象在老生代中只佔較小部分,這是爲何採用標記清除算法的緣由。

3.3.3 標記清楚算法的問題

主要問題是每一次進行標記清除回收後,內存空間會出現不連續的狀態

  • 這種內存碎片會對後續內存分配形成問題,極可能出現須要分配一個大對象的狀況,這時全部的碎片空間都沒法完成這次分配,就會提早觸發垃圾回收,而此次回收是沒必要要的。
  • 爲了解決碎片問題,標記整理被提出來。就是在對象被標記死亡後,在整理的過程當中,將活着的對象往一端移動,移動完成後,直接清理掉邊界外的內存。

3.3.4 哪些狀況會形成V8沒法當即回收內存

閉包和全局變量

3.3.5 請談一下內存泄漏是什麼,以及常見內存泄漏的緣由,和排查的方法

什麼是內存泄漏

  • 內存泄漏(Memory Leak)指因爲疏忽或錯誤形成程序未能釋放已經再也不使用的內存的狀況。
  • 若是內存泄漏的位置比較關鍵,那麼隨着處理的進行可能持有愈來愈多的無用內存,這些無用的內存變多會引發服務器響應速度變慢。
  • 嚴重的狀況下致使內存達到某個極限(多是進程的上限,如 v8 的上限;也多是系統可提供的內存上限)會使得應用程序崩潰。 常見內存泄漏的緣由 內存泄漏的幾種狀況:

1、全局變量

a = 10;  
//未聲明對象。  
global.b = 11;  
//全局變量引用 
這種比較簡單的緣由,全局變量直接掛在 root 對象上,不會被清除掉。
複製代碼

2、閉包

function out() {  
    const bigData = new Buffer(100);  
    inner = function () {  
        
    }  
} 
複製代碼

閉包會引用到父級函數中的變量,若是閉包未釋放,就會致使內存泄漏。上面例子是 inner 直接掛在了 root 上,那麼每次執行 out 函數所產生的 bigData 都不會釋放,從而致使內存泄漏。

須要注意的是,這裏舉得例子只是簡單的將引用掛在全局對象上,實際的業務狀況多是掛在某個能夠從 root 追溯到的對象上致使的。

3、事件監聽

Node.js 的事件監聽也可能出現的內存泄漏。例如對同一個事件重複監聽,忘記移除(removeListener),將形成內存泄漏。這種狀況很容易在複用對象上添加事件時出現,因此事件重複監聽可能收到以下警告:

emitter.setMaxListeners() to increase limit 
複製代碼

例如,Node.js 中 Agent 的 keepAlive 爲 true 時,可能形成的內存泄漏。當 Agent keepAlive 爲 true 的時候,將會複用以前使用過的 socket,若是在 socket 上添加事件監聽,忘記清除的話,由於 socket 的複用,將致使事件重複監遵從而產生內存泄漏。

原理上與前一個添加事件監聽的時候忘了清除是同樣的。在使用 Node.js 的 http 模塊時,不經過 keepAlive 複用是沒有問題的,複用了之後就會可能產生內存泄漏。因此,你須要瞭解添加事件監聽的對象的生命週期,並注意自行移除。

排查方法

想要定位內存泄漏,一般會有兩種狀況:

  • 對於只要正常使用就能夠重現的內存泄漏,這是很簡單的狀況只要在測試環境模擬就能夠排查了。

  • 對於偶然的內存泄漏,通常會與特殊的輸入有關係。想穩定重現這種輸入是很耗時的過程。若是不能經過代碼的日誌定位到這個特殊的輸入,那麼推薦去生產環境打印內存快照了。

  • 須要注意的是,打印內存快照是很耗 CPU 的操做,可能會對線上業務形成影響。 快照工具推薦使用 heapdump 用來保存內存快照,使用 devtool 來查看內存快照。

  • 使用 heapdump 保存內存快照時,只會有 Node.js 環境中的對象,不會受到干擾(若是使用 node-inspector 的話,快照中會有前端的變量干擾)。

  • PS:安裝 heapdump 在某些 Node.js 版本上可能出錯,建議使用 npm install heapdump -target=Node.js 版原本安裝。

四、Buffer模塊

4.1 新建Buffer會佔用V8分配的內存嗎

不會,Buffer屬於堆外內存,不是V8分配的。

4.2 Buffer.alloc和Buffer.allocUnsafe的區別

Buffer.allocUnsafe建立的 Buffer 實例的底層內存是未初始化的。 新建立的 Buffer 的內容是未知的,可能包含敏感數據。 使用 Buffer.alloc() 能夠建立以零初始化的 Buffer 實例。

4.3 Buffer的內存分配機制

爲了高效的使用申請來的內存,Node採用了slab分配機制。slab是一種動態的內存管理機制。 Node以8kb爲界限來來區分Buffer爲大對象仍是小對象,若是是小於8kb就是小Buffer,大於8kb就是大Buffer。

例如第一次分配一個1024字節的Buffer,Buffer.alloc(1024),那麼此次分配就會用到一個slab,接着若是繼續Buffer.alloc(1024),那麼上一次用的slab的空間尚未用完,由於總共是8kb,1024+1024 = 2048個字節,沒有8kb,因此就繼續用這個slab給Buffer分配空間。

若是超過8kb,那麼直接用C++底層地宮的SlowBuffer來給Buffer對象提供空間。

4.4 Buffer亂碼問題

例如一個份文件test.md裏的內容以下:

牀前明月光,疑是地上霜,舉頭望明月,低頭思故鄉
複製代碼

咱們這樣讀取就會出現亂碼:

var rs = require('fs').createReadStream('test.md', {highWaterMark: 11});
// 牀前明???光,疑???地上霜,舉頭???明月,???頭思故鄉
複製代碼

通常狀況下,只須要設置rs.setEncoding('utf8')便可解決亂碼問題

五、webSocket

5.1 webSocket與傳統的http有什麼優點

  • 客戶端與服務器只須要一個TCP鏈接,比http長輪詢使用更少的鏈接
  • webSocket服務端能夠推送數據到客戶端
  • 更輕量的協議頭,減小數據傳輸量

5.2 webSocket協議升級時什麼,能簡述一下嗎?

首先,WebSocket鏈接必須由瀏覽器發起,由於請求協議是一個標準的HTTP請求,格式以下:

GET ws://localhost:3000/ws/chat HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: Upgrade
Origin: http://localhost:3000
Sec-WebSocket-Key: client-random-string
Sec-WebSocket-Version: 13
複製代碼

該請求和普通的HTTP請求有幾點不一樣:

  • GET請求的地址不是相似/path/,而是以ws://開頭的地址;
  • 請求頭Upgrade: websocket和Connection: Upgrade表示這個鏈接將要被轉換爲WebSocket鏈接;
  • Sec-WebSocket-Key是用於標識這個鏈接,並不是用於加密數據;
  • Sec-WebSocket-Version指定了WebSocket的協議版本。

隨後,服務器若是接受該請求,就會返回以下響應:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: server-random-string
複製代碼

該響應代碼101表示本次鏈接的HTTP協議即將被更改,更改後的協議就是Upgrade: websocket指定的WebSocket協議。

六、https

6.1 https用哪些端口進行通訊,這些端口分別有什麼用

  • 443端口用來驗證服務器端和客戶端的身份,好比驗證證書的合法性
  • 80端口用來傳輸數據(在驗證身份合法的狀況下,用來數據傳輸)

6.2 身份驗證過程當中會涉及到密鑰, 對稱加密,非對稱加密,摘要的概念,請解釋一下

  • 密鑰:密鑰是一種參數,它是在明文轉換爲密文或將密文轉換爲明文的算法中輸入的參數。密鑰分爲對稱密鑰與非對稱密鑰,分別應用在對稱加密和非對稱加密上。

  • 對稱加密:對稱加密又叫作私鑰加密,即信息的發送方和接收方使用同一個密鑰去加密和解密數據。對稱加密的特色是算法公開、加密和解密速度快,適合於對大數據量進行加密,常見的對稱加密算法有DES、3DES、TDEA、Blowfish、RC5和IDEA。

  • 非對稱加密:非對稱加密也叫作公鑰加密。非對稱加密與對稱加密相比,其安全性更好。對稱加密的通訊雙方使用相同的密鑰,若是一方的密鑰遭泄露,那麼整個通訊就會被破解。而非對稱加密使用一對密鑰,即公鑰和私鑰,且兩者成對出現。私鑰被本身保存,不能對外泄露。公鑰指的是公共的密鑰,任何人均可以得到該密鑰。用公鑰或私鑰中的任何一個進行加密,用另外一個進行解密。

  • 摘要: 摘要算法又稱哈希/散列算法。它經過一個函數,把任意長度的數據轉換爲一個長度固定的數據串(一般用16進制的字符串表示)。算法不可逆。

6.3 爲何須要CA機構對證書籤名

若是不簽名會存在中間人攻擊的風險,簽名以後保證了證書裏的信息,好比公鑰、服務器信息、企業信息等不被篡改,可以驗證客戶端和服務器端的「合法性」。

6.4 https驗證身份也就是TSL/SSL身份驗證的過程

簡要圖解以下

七、進程通訊

7.1 請簡述一下node的多進程架構

面對node單線程對多核CPU使用不足的狀況,Node提供了child_process模塊,來實現進程的複製,node的多進程架構是主從模式,以下所示:

var fork = require('child_process').fork;
var cpus = require('os').cpus();
for(var i = 0; i < cpus.length; i++){
    fork('./worker.js');
}
複製代碼

在linux中,咱們經過ps aux | grep worker.js查看進程

這就是著名的主從模式,Master-Worker

7.2 請問建立子進程的方法有哪些,簡單說一下它們的區別

建立子進程的方法大體有:

  • spawn(): 啓動一個子進程來執行命令
  • exec(): 啓動一個子進程來執行命令,與spawn()不一樣的是其接口不一樣,它有一個回調函數獲知子進程的情況
  • execFlie(): 啓動一個子進程來執行可執行文件
  • fork(): 與spawn()相似,不一樣電在於它建立Node子進程須要執行js文件
  • spawn()與exec()、execFile()不一樣的是,後二者建立時能夠指定timeout屬性設置超時時間,一旦建立的進程超過設定的時間就會被殺死
  • exec()與execFile()不一樣的是,exec()適合執行已有命令,execFile()適合執行文件。

7.3 請問你知道spawn在建立子進程的時候,第三個參數有一個stdio選項嗎,這個選項的做用是什麼,默認的值是什麼。

  • 選項用於配置在父進程和子進程之間創建的管道。
  • 默認狀況下,子進程的 stdin、 stdout 和 stderr 會被重定向到 ChildProcess 對象上相應的 subprocess.stdin、subprocess.stdout 和 subprocess.stderr 流。
  • 這至關於將 options.stdio 設置爲 ['pipe', 'pipe', 'pipe']。

7.4 請問實現一個node子進程被殺死,而後自動重啓代碼的思路

  • 在建立子進程的時候就讓子進程監聽exit事件,若是被殺死就從新fork一下
var createWorker = function(){
    var worker = fork(__dirname + 'worker.js')
    worker.on('exit', function(){
        console.log('Worker' + worker.pid + 'exited');
        // 若是退出就建立新的worker
        createWorker()
    })
}
複製代碼

7.5 在7.4的基礎上,實現限量重啓,好比我最多讓其在1分鐘內重啓5次,超過了就報警給運維

  • 思路大概是在建立worker的時候,就判斷建立的這個worker是否在1分鐘內重啓次數超過5次
  • 因此每一次建立worker的時候都要記錄這個worker 建立時間,放入一個數組隊列裏面,每次建立worker都去取隊列裏前5條記錄
  • 若是這5條記錄的時間間隔小於1分鐘,就說明到了報警的時候了

7.6 如何實現進程間的狀態共享,或者數據共享

我本身沒用過Kafka這類消息隊列工具,問了java,能夠用相似工具來實現進程間通訊,更好的方法歡迎留言

八、中間件

8.1 若是使用過koa、egg這兩個Node框架,請簡述其中的中間件原理,最好用代碼表示一下

  • 上面是在網上找的一個示意圖,就是說中間件執行就像洋蔥同樣,最先use的中間件,就放在最外層。處理順序從左到右,左邊接收一個request,右邊輸出返回response
  • 通常的中間件都會執行兩次,調用next以前爲第一次,調用next時把控制傳遞給下游的下一個中間件。當下遊再也不有中間件或者沒有執行next函數時,就將依次恢復上游中間件的行爲,讓上游中間件執行next以後的代碼
  • 例以下面這段代碼
const Koa = require('koa')
const app = new Koa()
app.use((ctx, next) => {
    console.log(1)
    next()
    console.log(3)
})
app.use((ctx) => {
    console.log(2)
})
app.listen(3001)
執行結果是1=>2=>3
複製代碼

koa中間件實現源碼大體思路以下:

// 注意其中的compose函數,這個函數是實現中間件洋蔥模型的關鍵
// 場景模擬
// 異步 promise 模擬
const delay = async () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve();
    }, 2000);
  });
}
// 中間間模擬
const fn1 = async (ctx, next) => {
  console.log(1);
  await next();
  console.log(2);
}
const fn2 = async (ctx, next) => {
  console.log(3);
  await delay();
  await next();
  console.log(4);
}
const fn3 = async (ctx, next) => {
  console.log(5);
}

const middlewares = [fn1, fn2, fn3];

// compose 實現洋蔥模型
const compose = (middlewares, ctx) => {
  const dispatch = (i) => {
    let fn = middlewares[i];
    if(!fn){ return Promise.resolve() }
    return Promise.resolve(fn(ctx, () => {
      return dispatch(i+1);
    }));
  }
  return dispatch(0);
}

compose(middlewares, 1);
複製代碼

九、其它

如今在從新過一遍node 12版本的主要API,有不少新發現,好比說

  • fs.watch這個模塊,事件的回調函數有一個參數是觸發的事件名稱,可是呢,不管我增刪改,都是觸發rename事件(若是更改是update事件,刪除delete事件,重命名是rename事件,這樣語義明晰該多好)。後來網上找到一個node-watch模塊,此模塊增刪改都有對應的事件, 而且還高效的支持遞歸watch 文件。
  • util模塊有個promisify方法,可讓一個遵循異常優先的回調風格的函數,即 (err, value) => ... 回調函數是最後一個參數,返回一個返回值是一個 promise 版本的函數。
const util = require('util');
const fs = require('fs');

const stat = util.promisify(fs.stat);
stat('.').then((stats) => {
  // 處理 `stats`。
}).catch((error) => {
  // 處理錯誤。
});
複製代碼

9.1 雜想

  • crypto模塊,能夠考察基礎的加密學知識,好比摘要算法有哪些(md5, sha1, sha256,加鹽的md5,sha256等等),接着能夠問如何用md5本身模擬一個加鹽的md5算法, 接着能夠問加密算法(crypto.createCiphe)中的aes,eds算法的區別,分組加密模式有哪些(好比ECB,CBC,爲何ECB不推薦),node裏的分組加密模式是哪一種(CMM),這些加密算法裏的填充和向量是什麼意思,接着能夠問數字簽名和https的流程(爲何須要CA,爲何要對稱加密來加密公鑰等等)
  • tcp/ip,能夠問不少基礎問題,好比鏈路層經過什麼協議根據IP地址獲取物理地址(arp),網關是什麼,ip裏的ICMP協議有什麼用,tcp的三次握手,四次分手的過程是什麼,tcp如何控制重發,網絡堵塞TCP會怎麼辦等等,udp和tcp的區別,udp裏的廣播和組播是什麼,組播在node裏經過什麼模塊實現。
  • os,操做系統相關基礎,io的流程是什麼(從硬盤裏讀取數據到內核的內存中,而後內核的內存將數據傳入到調用io的應用程序的進程內存中),馮諾依曼體系是什麼,進程和線程的區別等等(我最近在看馬哥linux教程,由於本身不是科班出身,聽了不少基礎的計算機知識,受益不淺,建議去bilibili看)
  • linux相關操做知識(node涉及到後臺,雖然是作中臺,不涉及數據庫,可是基本的linux操做仍是要會的)
  • node性能監控(本身也正在學習中)
  • 測試,由於用的egg框架,有很完善的學習單元測試的文檔,省略這部分
  • 數據庫能夠問一些好比事務的等級有哪些,mysql默認的事務等級是什麼,會產生什麼問題,而後考一些mysql查詢的筆試題。。。和經常使用優化技巧,node的mysql的orm工具使用過沒有。。。(好比我本身是看的尚硅谷mysql初級+高級視頻,書是看的mysql必知必會,我本身出於愛好學習一下。。。沒有實戰過)
相關文章
相關標籤/搜索