1、在開發(fā)Node.js的時(shí)候異步的嵌套很麻煩,有人叫回調(diào)地獄或回調(diào)黑洞,如何解決這一問題?
答:promise async await
多層嵌套:
const express = require('express');
const app = express();
const request = require('request');
app.get('/data', function(req, res) {
request('php地址1', funciton(error, response, body) {
request('php地址3', function(error, response, body) {
request('php地址3', function(error, response, body) {
...
res.json({
data: body
})
})
})
})
})
使用async和await:
const express = require('express');
const app = express();
const request = require('request');
const rp = require('request-promise');
app.get('/data', async function(req, res) {
const result1 = await rp('php地址1');
const result2 = await rp('php地址2');
const result3 = await rp('php地址3');
console.log(result1 + result2 + result3);
})
2、如何解釋Node.js適合IO密集型不適合CPU密集型?
答:
- CPU密集型:計(jì)算等邏輯判斷的操作,如:壓縮、解壓、加密和解密等。
-
I/O密集型:存取設(shè)備,網(wǎng)絡(luò)設(shè)施的讀取操作,如:文件的存取,http等網(wǎng)絡(luò)操作,數(shù)據(jù)庫操作等。
Node.js 執(zhí)行是單線程的,如果執(zhí)行 CPU 密集的任務(wù)就會(huì)阻塞后續(xù)代碼,且單線程無法充分利用 CPU 多核資源。而異步 I/O 是多線程的,在工作線程上執(zhí)行,不會(huì)阻塞執(zhí)行線程,執(zhí)行效率更高。
3、畫出Node.js的異步時(shí)間回調(diào)機(jī)制的實(shí)現(xiàn),并解釋原理。
答:如下圖:
原理:
(1)V8引擎解析JavaScript腳本。
(2)解析后的代碼,調(diào)用Node API。
(3)libuv庫負(fù)責(zé)Node API的執(zhí)行。它將不同的任務(wù)分配給不同的線程,形成一個(gè)Event Loop(事件循環(huán)),以異步的方式將任務(wù)的執(zhí)行結(jié)果返回給V8引擎。
(4)V8引擎再將結(jié)果返回給用戶。
4、開發(fā)一個(gè)完整的Node.js程序,有UI層、service層、DAO層、MODEL層等,我們要在交給QA測試前需要編寫測試用例。測試用例一般遵循測試金字塔(測試金字塔指的是編寫測試用例時(shí),底層的單元測試應(yīng)該永遠(yuǎn)比上層的端到端測試用例要多,如下圖),請問如下三個(gè)階段,都用了什么樣的技術(shù)進(jìn)行測試用例的編寫?
答:
unit 指的是一小塊業(yè)務(wù)邏輯,可以使一個(gè)小組件、一個(gè)小函數(shù)、一個(gè)小類等
通常用karma+jasmine測試
service 主要是用 mocha+chai 異步測試
UI 主要是用 selenium-webdriver或者nightwatch
5、有人說Node.js是玩具,寫錯(cuò)一處整個(gè)網(wǎng)站都掛掉,有什么解決辦法?
答:
① 使用errorHandler處理對應(yīng)的錯(cuò)誤,如404等
② 用SafeRequest替代request
③ 容錯(cuò),PM2 0秒熱啟功能(守護(hù)進(jìn)程)
④ 電話,郵件,日志等出錯(cuò)的通知機(jī)制
⑤ 用process提供了一個(gè)事件uncaughtException進(jìn)行抓取異常進(jìn)行處理
process.on('uncaughtException', function(err){
console.log(err);
console.log(err.stack);
});
⑥ 企業(yè)級錯(cuò)誤監(jiān)測產(chǎn)品,如騰訊的bugly
6、寫出知道的HTTP常用請求報(bào)頭,并寫出常見的HTTP status code含義?
答:常用的HTTP請求報(bào)頭(Request Headers)
① Accept-Charset:標(biāo)明瀏覽器可以使用的字符集(如ISO-8859-1).
② Accept-Encoding:詳細(xì)列出客戶端能處理的編碼類型(gzip,compress是兩種常見的值),一般來講花在解碼上的時(shí)間要遠(yuǎn)遠(yuǎn)小于傳輸?shù)拈_銷。
③ Accept-Language:在servlet能夠以多種語言生產(chǎn)結(jié)果時(shí),列出客戶程序首選的語言。這個(gè)報(bào)頭的值應(yīng)該是標(biāo)準(zhǔn)語言代碼的一種,比如en, en-us, da等。
④ Connection:標(biāo)明客戶是否能夠處理持續(xù)性HTTP連接。持續(xù)性(Keep-Alive)是默認(rèn)的選項(xiàng)。
⑤ Content-Length:只適用于POST請求,用來給定POST數(shù)據(jù)的大小,以字節(jié)為單位。
⑥ Cookie:這個(gè)報(bào)頭向服務(wù)器返回cookie,這些cookie是之前服務(wù)器發(fā)送給瀏覽器的。使用request.getCookies讀取這個(gè)報(bào)頭。
⑦ Host:在HTTP1.1中,瀏覽器和其他客戶端程序需要制定這個(gè)報(bào)頭,它標(biāo)明原始URL中給出的主機(jī)名和端口號(hào)。
⑧ Use-Agent標(biāo)識(shí)生產(chǎn)請求的瀏覽器或其他客戶端程序,根據(jù)這個(gè)報(bào)頭,可以針對不同類型的瀏覽器返回不同的內(nèi)容。
7、請用Koa2實(shí)現(xiàn)基本的服務(wù)端,并輸出Hello world,且實(shí)現(xiàn)功能測試。
答:代碼如下:
const Koa = require('koa');
const app = new Koa();
app.use(ctx => {
ctx.body = Hello world'';
}
app.listen(3000);
功能測試代碼:
const app = require('app');
const request = require('supertest').agent(app.listen());
describe('Hello world', function(){
it('should say "Hello world" ', function(done){
request
.get('/')
.expect(200)
.expect('Hello world', done);
})
})
8、描述何種情況下會(huì)造成Node.js的內(nèi)存泄漏,如何檢測?
答:① 全局變量
a = 1;
這種比較簡單的原因,全局變量直接掛在 root 對象上,不會(huì)被清除掉。
② 閉包
function outter(){
var a = 1;
return function inner(b){
console.log(a+b);
}
}
var outter2 = outter();
outter2(5);
閉包會(huì)引用到父級函數(shù)中的變量,如果閉包未釋放,就會(huì)導(dǎo)致內(nèi)存泄漏。
③ 過大的數(shù)組循環(huán)
var arr=[];
for(var i = 0; i<10000; i++){
arr.push(i);
}
9、描述一下當(dāng)下新時(shí)代的前端中Node.js的作用及其實(shí)際應(yīng)用?以及一般Node.js項(xiàng)目文件夾的劃分?
答:作用及應(yīng)用:
① 作為數(shù)據(jù)中間代理層,轉(zhuǎn)發(fā)數(shù)據(jù)
② 為前端提供路由
③ 封裝后端接口
文件夾的劃分:
models:請求數(shù)據(jù)
controller:路由配置
public:靜態(tài)資源
views:模板文件
libs:公共文件
config:配置文件
test:測試文件
app.js啟動(dòng)文件
10、瀏覽器緩存機(jī)制。
答:圖片來自:瀏覽器緩存機(jī)制
瀏覽器第一次請求:
瀏覽器再次請求時(shí):