【前端面試題】—53道常見(jiàn)NodeJS基礎(chǔ)面試題(附答案)

var express = require("express");要導(dǎo)入 JavaScript文件,需要使用文件的路徑,如下所示:
var demo = require("./demo.js");21、npm的作用是什么?
npm是同 Node .js一起安裝的包管理工具,能解決 Node. js代碼部署上的很多問(wèn)題。常見(jiàn)的使用場(chǎng)景有以下幾種。
(1)允許用戶從npm服務(wù)器下載別人編寫的第三方包到本地。
(2)允許用戶從npm服務(wù)器下載并安裝別人編寫的命令行程序到本地。
(3)允許用戶將自己編寫的包或命令行程序上傳到npm服務(wù)器供別人使用。
22、什么是 EventEmitter?
EventEmitter是 Node. js中一個(gè)實(shí)現(xiàn)觀察者模式的類,主要功能是訂閱和發(fā)布消息,用于解決多模塊交互而產(chǎn)生的模塊之間的耦合問(wèn)題.
23、如何實(shí)現(xiàn)一個(gè) EventEmitter?
可通過(guò)3步實(shí)現(xiàn) EventEmitter定義一個(gè)子類,通過(guò)寄生組合式繼承,繼承 EventEmitter
父類,代碼如下。
var Util= require('util' );var EventEmitter= require ('events' ) .EventEmitter;function IcktEmitter () {EventEmitter .apply(this, arguments)}Util.inherits(IcktEmitter, EventEmitter);var ie = new IcktEmitter ( ) ;ie.on('icketang', function(data){console.log('接收到消息',data )})ie.emit(' icketang','來(lái)自有課網(wǎng)的消息');
24、EventEmitter有哪些典型應(yīng)用?
有以下應(yīng)用。
(1)在模塊間傳遞消息。
(2)在回調(diào)函數(shù)內(nèi)外傳遞消息。
(3)處理流數(shù)據(jù),因?yàn)榱魇窃?EventEmitter的基礎(chǔ)上實(shí)現(xiàn)的。
(4)運(yùn)用觀察者模式收發(fā)消息的相關(guān)應(yīng)用。
25、如何捕獲 EventEmitter的錯(cuò)誤事件?
當(dāng)發(fā)布error消息的時(shí)候,如果沒(méi)有注冊(cè)該事件,應(yīng)用程序會(huì)拋出錯(cuò)誤并中斷執(zhí)行。所以要監(jiān)聽(tīng)error事件,代碼如下。
var ie= new IcktEmitter ( );ie .on('error ', function(err){conso1e.1og ( '接收到錯(cuò)誤的信息',err )})ie.emit(' error','來(lái)自ie1的錯(cuò)誤消息');
26、Node. js中的流是什么?
流(Stream)是基于 EventEmitter的數(shù)據(jù)管理模式,由各種不同的抽象接口組成,主要包括可寫、可讀、可讀寫、可轉(zhuǎn)換等類型。
27、使用流有什么好處?
流是非阻塞式數(shù)據(jù)處理模式,可以提升效率,節(jié)省內(nèi)存,有助于處理管道且可擴(kuò)展等。
28、流有哪些典型應(yīng)用?
流在文件讀寫、網(wǎng)絡(luò)請(qǐng)求、數(shù)據(jù)轉(zhuǎn)換、音頻、視頻等方面有很廣泛的應(yīng)用。
29、如何捕獲流的錯(cuò)誤事件?
監(jiān)聽(tīng)error事件,方法與訂閱 EventEmitter的error事件相似。
30、有哪些常用 Stream流?分別什么時(shí)候使用?
Readable流為可讀流,在作為輸入數(shù)據(jù)源時(shí)使用;Writable流為可寫流,在作為輸岀源時(shí)使用;Duplex流為可讀寫流,它作為輸岀源被寫入,同時(shí)又作為輸入源被后面的流讀出。
Transform流和 Duplex流一樣,都是雙向流,區(qū)別是 Transfrom流只需要實(shí)現(xiàn)一個(gè)函數(shù) _transfrom( chunk, encoding, callback);而 Duplex流需要分別實(shí)現(xiàn)_read(size )函數(shù)和_write( chunk, encoding, callback )函數(shù)。
31、如何實(shí)現(xiàn)一個(gè) Writable流?
實(shí)現(xiàn) Writable流分成3步
(1)引入 Writable模塊。
(2)繼承 Writable模塊。
(3)實(shí)現(xiàn) _write(chunk, encoding, callback )寫入函數(shù)。
代碼如下。
//引入 Writable模塊var Writable= require('stream').Writable;var Util = require('util');//繼承 Writable模塊function IcktWritable( ) {Writable. apply(this, arguments ) ;}Util.inherits ( IcktWritable, Writable ) ;//實(shí)現(xiàn) write函數(shù)IcktWritable. prototype. _write = function ( data, encoding, callback ) {console.log ('被寫入的數(shù)據(jù)是:' ,data. toString ( ) )callback ( )}var iw= new IcktWritable ( ) ;for (var i=0;i< 5 ;i++ ) {iw. write('有課網(wǎng)'+i,'utf8")}iw,end('學(xué)技能就上有課網(wǎng)' );
32、內(nèi)置的fs模塊架構(gòu)由哪幾部分組成?
fs模塊主要由下面幾部分組成。
(1) POSIX文件 Wrapper,對(duì)應(yīng)操作系統(tǒng)的原生文件操作。
(2)文件流,fs. createReadStream和 fs.createWriteStrean。
(3)同步文件讀寫, fs.readFileSync和fs.writeFileSync。
(4)異步文件讀寫, fs.readFile和fs.writeFile。
33、讀寫一個(gè)文件有多少種方法?
總體來(lái)說(shuō),有4種方法。
(1) POSIX式底層讀寫。
(2)流式讀寫。
(3)同步文件讀寫。
(4)異步文件讀寫。
34、如何讀取JSON配置文件?
主要有兩種方式。第一種是利用 Node. js內(nèi)置的 require( data.json!)機(jī)制,直接得到 Javascript對(duì)象;
第二種是讀入文件內(nèi)容,然后用JSON. parse( content)轉(zhuǎn)換成 JavaScript對(duì)象。
二者的區(qū)別是,對(duì)于第一種方式,如果多個(gè)模塊都加載了同一個(gè)JSON文件,那么其中一個(gè)改變了 JavaScript對(duì)象,其他也跟著改變,這是由 Node.js模塊的緩存機(jī)制造成的,緩存中只有一個(gè) JavaScript模塊對(duì)象;
第二種方式則可以隨意改變加載后的JavaScript變量,而且各模塊互不影響,因?yàn)樗鼈兌际仟?dú)立的,存儲(chǔ)的是多個(gè) JavaScript對(duì)象。
35、fs.watch和 fs.watchFile有什么區(qū)別?
二者主要用來(lái)監(jiān)聽(tīng)文件變動(dòng),fs.watch利用操作系統(tǒng)原生機(jī)制來(lái)監(jiān)聽(tīng),可能不適用網(wǎng)絡(luò)文件系統(tǒng);fs. watchFile則定期檢查文件狀態(tài)變更,適用于網(wǎng)絡(luò)文件系統(tǒng),但是與fs.watch相比有些慢,因?yàn)樗徊捎脤?shí)時(shí)機(jī)制。
36、為什么需要子進(jìn)程?
Node. js是異步非阻塞的,這對(duì)高并發(fā)非常有效。可是我們還有其他一些常用的需求,比如和操作系統(tǒng) shell命令交互,調(diào)用可執(zhí)行文件,創(chuàng)建子進(jìn)程,進(jìn)行阻塞式訪問(wèn)或高CPU計(jì)算等,子進(jìn)程就是為滿足這些需求而產(chǎn)生的。顧名思義,子進(jìn)程就是把 Node. js阻塞的工作交給子進(jìn)程去做。
37、exec、 execFile、 spawn和fork都是做什么用的?
它們的作用分別如下。
exec可以用操作系統(tǒng)原生的方式執(zhí)行各種命令,如管道 cat ab. txt | grep hello。
execFile用于執(zhí)行一個(gè)文件。
spawn負(fù)責(zé)在流式和操作系統(tǒng)之間進(jìn)行交互。
fork負(fù)責(zé)在兩個(gè) Node. js程序( JavaScript)之間進(jìn)行交互。
38、如何實(shí)現(xiàn)一個(gè)簡(jiǎn)單的命令行交互程序?
實(shí)現(xiàn)代碼如下。
var cp = require (' child process );//執(zhí)行指令var child= cp .spawn('echo', ['hello, ''] );// child.stdout是輸入流, process. stdout是輸出流//子進(jìn)程的輸出流作為當(dāng)前程序的輸入流,然后重定向到當(dāng)前程序的控制器輸出child. stdout. pipe(process. stdout)
39、兩個(gè) Node. js程序之間如何交互?
通過(guò)fork實(shí)現(xiàn)父子程序之間的交互。子程序用 process.on、 process. send訪問(wèn)父程序,父程序用 child.on、 child.send訪問(wèn)子程序。
關(guān)于 parent. JS的示例代碼如下。
var cp = require (' child_process' ) ;var child= cp.fork ('./child. js' );child .on('message', function(msg){console.1og('子程序發(fā)送的數(shù)據(jù):',msg )})child.send ( '來(lái)自父程序發(fā)送的數(shù)據(jù)' )
關(guān)于 child .js的示例代碼如下。
process .on ( 'message' , function(msg){conso1e.1og ( '父程序發(fā)送的數(shù)據(jù): ' , msg )process.send ( '來(lái)自子程序發(fā)送的數(shù)據(jù)' )
40、如何讓一個(gè) JavaScript文件變得像 Linux命令一樣可執(zhí)行?
具體步驟如下。
(1)在文件頭部加入#!/ bin/sh
如 icketang40.js#!/bin/shecho'有課網(wǎng)— 技能學(xué)習(xí)就上有課網(wǎng);
(2)用 chmod命令把名為 icketang40的 JavaScript文件改為可執(zhí)行文件。
chmod + x icketang40.js(3)進(jìn)入文件目錄,在命令行輸入 icketang40.js就相當(dāng)于執(zhí)行 node icketang40.js
$ ./icketang40.js執(zhí)行結(jié)果。
41、子進(jìn)程和進(jìn)程的 stdin、 stdout、 stderror是樣的嗎?
概念都是一樣的。stdin、 stdout、 stderror分別是輸入、輸出、錯(cuò)誤。三者都是流。區(qū)別是在父進(jìn)程里,子進(jìn)程的 stdout是輸入流, stdin是輸出流。
42、async都有哪些常用方法?分別怎么用?
async是一個(gè) JavaScript類庫(kù),它的目的是解決 JavaScript中異常流程難以控制的問(wèn)題。async不僅在 Node. js里適用,還可以用在瀏覽器中。其常用方法和用法如下。
具體代碼如下所示。
var async = require('async ');var date = Date .now ( );
(1) async. parallel:并行執(zhí)行完多個(gè)函數(shù)后,調(diào)用結(jié)束函數(shù)。不用等到前一個(gè)函數(shù)。執(zhí)行完再執(zhí)行下一個(gè)函數(shù)。
async .parallel ( [function ( callback ) {setTimeout (function () {console. log('process one', Date. now ( ) - date)callback(null, 'msg one')},2000)},function ( callback ){setTimeout ( function () {console. log('process tow', Date .now ( ) - date )callback ( null, 'msg tow' )},1000)}], function(err, result){console. log(err, result, 'done ')})
(2) async.series:串行執(zhí)行完多個(gè)函數(shù)后,調(diào)用結(jié)束函數(shù)。前面一個(gè)函數(shù)執(zhí)行完之后,就會(huì)立即執(zhí)行下一個(gè)函數(shù)。
async .series ( [function ( callback ) {setTimeout ( function () {console. log ( 'process one ', Date. now ( ) - date )callback ( null, ' msg one' )},2000 )},function ( callback ) {setTimeout ( function () {console. log ( 'process tow', Date. now ( ) - date )callback ( null, 'msg tow ' )},1000 )}] , function (err, result ) {console. log(err, result, 'done')})
(3) async. waterfall:依次執(zhí)行多個(gè)函數(shù),前一個(gè)函數(shù)的執(zhí)行結(jié)果作為后一個(gè)函數(shù)執(zhí)行時(shí)的參數(shù)。
async .waterfall ( [function ( callback ) {setTimeout ( function () {console. log('process one, Date. now()- date)callback(null, 'msg one')},2000)},function(argl, callback){setTimeout (function(){console. log('process tow, Date. now ( ) - date, argl )callback(null, 'msg tow')},1000)}] , function(err, result){console. log(err, result, 'done ')})
43、express項(xiàng)目的目錄大致是什么結(jié)構(gòu)的?
首先,執(zhí)行安裝 express的指令:npm install express-generator-g。
然后,通過(guò) express指令創(chuàng)建項(xiàng)目:express icketang。
創(chuàng)建的項(xiàng)目目錄結(jié)構(gòu)如下。
./app.js 應(yīng)用核心配置文件(入口文件)
./bin 存放啟動(dòng)項(xiàng)目的腳本文件
./ package.json 存儲(chǔ)項(xiàng)目的信息及模塊依賴
./public 靜態(tài)文件(css、js、img等)
./routes 路由文件(MVC中的 contro1ler)
./views 頁(yè)面文件(jade模板)
44、express常用函數(shù)有哪些?
常用函數(shù)有以下幾個(gè)
express .Router—路由組件
app.get—路由定向。
app. configure——配置。
app.set一設(shè)定參數(shù)。
app.use——使用中間件。
45、express中如何獲取路由的參數(shù)?
執(zhí)行的命令如下
/users/:name使用 req.params.name來(lái)獲取;使用req.body.username來(lái)獲得表單傳入?yún)?shù) username;express的路由支持常用通配符有?、+、*、( )。
46、express response有哪些常用方法?
常用方法有以下幾個(gè)。
res. download( ),彈出文件下載。
res.end ( ),結(jié)束響應(yīng)。
res.json( ),返回json。
res.jsonp( ),返回 jsonp。
res .redirect ( ),重定向請(qǐng)求。
res .render ( ),渲染模板。
res.send ( ),返回多種形式數(shù)據(jù)。
res.sendFile ( ),返回文件。
res.sendStatus( ),返回狀態(tài)。
47、mongodb有哪些常用優(yōu)化措施?
常用優(yōu)化措施如下。
(1)優(yōu)化預(yù)讀。
(2)禁用NUMA。
(3)不要記錄訪問(wèn)時(shí)間等。
48、Redis的主要特點(diǎn)是什么?
主要特點(diǎn)如下。
(1) Redis支持?jǐn)?shù)據(jù)的持久化,可以將內(nèi)存中的數(shù)據(jù)保存在磁盤中,重啟的時(shí)候可以再次加載和使用。
(2) Redis不僅支持簡(jiǎn)單的鍵-值類型的數(shù)據(jù),同時(shí)還提供list、set、zset、hash等數(shù)據(jù)結(jié)構(gòu)的存儲(chǔ)。
(3) Redis支持?jǐn)?shù)據(jù)的備份,即主-從模式的數(shù)據(jù)備份。
49、Nginx和 Apache有什么區(qū)別?
Nginx是輕量級(jí)的,同樣的Web服務(wù)在 nginx中會(huì)占用更少的內(nèi)存和資源。Nginx抗并發(fā),處理請(qǐng)求的方式是異步非阻塞的,負(fù)載能力比 Apache高很多,而 Apache則是阻塞型的。
在高并發(fā)下 Nginx能保持低資源、低消耗、高性能,并且處理靜態(tài)文件比 Apache好。
Nginx的設(shè)計(jì)高度模塊化,編寫模塊相對(duì)簡(jiǎn)單,配置簡(jiǎn)潔。作為負(fù)載均衡服務(wù)器,支持7層負(fù)載均衡,是一個(gè)反向代理服務(wù)器。
社區(qū)活躍,各種高性能模塊出品迅速。Apache的 rewrite比 Nginx強(qiáng)大,模塊豐富。Apache發(fā)展得更為成熟,Bug很少,更加穩(wěn)定。
Apache對(duì)PHP的支持比較簡(jiǎn)單, Nginx需要配合其他后端使用。Apache處理動(dòng)態(tài)請(qǐng)求有優(yōu)勢(shì),擁有豐富的特性、成熟的技術(shù)和開(kāi)發(fā)社區(qū)。
50、說(shuō)說(shuō)線程與進(jìn)程的區(qū)別。
(1)一個(gè)程序至少有一個(gè)進(jìn)程,一個(gè)進(jìn)程至少有一個(gè)線程
(2)線程的劃分尺度小于進(jìn)程,使得多線程程序的并發(fā)性高。
(3)進(jìn)程在執(zhí)行過(guò)程中擁有獨(dú)立的內(nèi)存單元,而多個(gè)線程共享內(nèi)存,極大地提高了程序的運(yùn)行效率。
(4)線程在執(zhí)行過(guò)程中與進(jìn)程有區(qū)別。每個(gè)獨(dú)立的線程都有程序運(yùn)行的入口、順序執(zhí)行序列和程序的出口。但是線程不能夠獨(dú)立執(zhí)行,必須依存在應(yīng)用程序中,由應(yīng)用程序提供多個(gè)線程執(zhí)行控制。
(5)從邏輯角度來(lái)看,多線程的意義在于一個(gè)應(yīng)用程序中,有多個(gè)執(zhí)行部分可以同時(shí)執(zhí)行。但操作系統(tǒng)并沒(méi)有將多個(gè)線程看作多個(gè)獨(dú)立的應(yīng)用來(lái)實(shí)現(xiàn)進(jìn)程的調(diào)度、管理和資源分配。這是進(jìn)程和線程的主要區(qū)別。
51、你知道哪些 Node.js核心模塊?
EventEmitter 、Stream、FS、Net和全局對(duì)象等。
52、說(shuō)說(shuō) MySQL和 MongoDB的區(qū)別。
(1) MySQL是傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù), MongoDB則是非關(guān)系型數(shù)據(jù)庫(kù)。
(2) MongoDB以BSON結(jié)構(gòu)進(jìn)行存儲(chǔ),在存儲(chǔ)海量數(shù)據(jù)方面有著很明顯的優(yōu)勢(shì)。
(3)與傳統(tǒng)關(guān)系型數(shù)據(jù)庫(kù)相比, NoSQL有著非常顯著的性能和擴(kuò)展性優(yōu)勢(shì)。
(4)與傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)(如與 MySQL)相比, MongoDB的優(yōu)點(diǎn)如下。
弱一致性(最終一致),更能保證用戶的訪問(wèn)速度。
使用文檔結(jié)構(gòu)的存儲(chǔ)方式,能夠更便捷地獲取數(shù)據(jù)。
53、談?wù)剹:投训膮^(qū)別。
區(qū)別如下:
(1)棧( stack)區(qū)由編譯器自動(dòng)分配和釋放,存放函數(shù)的參數(shù)值、局部變量的值等。
堆(heap)區(qū)一般由程序員分配和釋放,若程序員不釋放,程序結(jié)束時(shí)可能由OS回收。
(2)堆(數(shù)據(jù)結(jié)構(gòu))可以被看成一棵樹(shù),如堆排序。棧(數(shù)據(jù)結(jié)構(gòu))是一種先進(jìn)后出的數(shù)據(jù)結(jié)構(gòu)。
推薦閱讀
【前端面試題】—18道有關(guān)混合開(kāi)發(fā)的面試題(附答案)
【前端面試題】—21道有關(guān)移動(dòng)端的面試題(附答案)

