欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Nodejs高并發(fā)原理示例詳解

 更新時(shí)間:2022年11月10日 14:16:25   作者:coder2028  
這篇文章主要為大家介紹了Nodejs高并發(fā)原理示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

導(dǎo)讀

ALL THE TIME,我們寫的的大部分javascript代碼都是在瀏覽器環(huán)境下編譯運(yùn)行的,因此可能我們對瀏覽器的事件循環(huán)機(jī)制了解比Node.JS的事件循環(huán)更深入一些,但是最近寫開始深入NodeJS學(xué)習(xí)的時(shí)候,發(fā)現(xiàn)NodeJS的事件循環(huán)機(jī)制和瀏覽器端有很大的區(qū)別,特此記錄來深入的學(xué)習(xí)了下,以幫助自己及小伙伴們忘記后查閱及理解。

什么是事件循環(huán)

首先我們需要了解一下最基礎(chǔ)的一些東西,比如這個(gè)事件循環(huán),事件循環(huán)是指Node.js執(zhí)行非阻塞I/O操作,盡管==JavaScript是單線程的==,但由于大多數(shù)==內(nèi)核都是多線程==的,Node.js會(huì)盡可能將操作裝載到系統(tǒng)內(nèi)核。因此它們可以處理在后臺(tái)執(zhí)行的多個(gè)操作。當(dāng)其中一個(gè)操作完成時(shí),內(nèi)核會(huì)告訴Node.js,以便Node.js可以將相應(yīng)的回調(diào)添加到輪詢隊(duì)列中以最終執(zhí)行。

當(dāng)Node.js啟動(dòng)時(shí)會(huì)初始化event loop, 每一個(gè)event loop都會(huì)包含按如下順序六個(gè)循環(huán)階段:

┌───────────────────────┐
┌─>│        timers         │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
│  │     I/O callbacks     │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
│  │     idle, prepare     │
│  └──────────┬────────────┘      ┌───────────────┐
│  ┌──────────┴────────────┐      │   incoming:   │
│  │         poll          │<─────┤  connections, │
│  └──────────┬────────────┘      │   data, etc.  │
│  ┌──────────┴────────────┐      └───────────────┘
│  │        check          │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
└──┤    close callbacks    │
   └───────────────────────┘
  • [x] 1. timers 階段: 這個(gè)階段執(zhí)行 setTimeout(callback) 和 setInterval(callback) 預(yù)定的 callback;
  • [x] 2. I/O callbacks 階段: 此階段執(zhí)行某些系統(tǒng)操作的回調(diào),例如TCP錯(cuò)誤的類型。 例如,如果TCP套接字在嘗試連接時(shí)收到 ECONNREFUSED,則某些* nix系統(tǒng)希望等待報(bào)告錯(cuò)誤。 這將操作將等待在==I/O回調(diào)階段==執(zhí)行;
  • [x] 3. idle, prepare 階段: 僅node內(nèi)部使用;
  • [x] 4. poll 階段: 獲取新的I/O事件, 例如操作讀取文件等等,適當(dāng)?shù)臈l件下node將阻塞在這里;
  • [x] 5. check 階段: 執(zhí)行 setImmediate() 設(shè)定的callbacks;
  • [x] 6. close callbacks 階段: 比如 socket.on(‘close’, callback) 的callback會(huì)在這個(gè)階段執(zhí)行;

事件循環(huán)詳解

這個(gè)圖是整個(gè) Node.js 的運(yùn)行原理,從左到右,從上到下,Node.js 被分為了四層,分別是 應(yīng)用層、V8引擎層Node API層 和 LIBUV層。

  • 應(yīng)用層: 即 JavaScript 交互層,常見的就是 Node.js 的模塊,比如 http,fs
  • V8引擎層: 即利用 V8 引擎來解析JavaScript 語法,進(jìn)而和下層 API 交互
  • NodeAPI層: 為上層模塊提供系統(tǒng)調(diào)用,一般是由 C 語言來實(shí)現(xiàn),和操作系統(tǒng)進(jìn)行交互 。
  • LIBUV層: 是跨平臺(tái)的底層封裝,實(shí)現(xiàn)了 事件循環(huán)、文件操作等,是 Node.js 實(shí)現(xiàn)異步的核心 。

每個(gè)循環(huán)階段內(nèi)容詳解

timers階段 一個(gè)timer指定一個(gè)下限時(shí)間而不是準(zhǔn)確時(shí)間,在達(dá)到這個(gè)下限時(shí)間后執(zhí)行回調(diào)。在指定時(shí)間過后,timers會(huì)盡可能早地執(zhí)行回調(diào),但系統(tǒng)調(diào)度或者其它回調(diào)的執(zhí)行可能會(huì)延遲它們。

  • 注意:技術(shù)上來說,poll 階段控制 timers 什么時(shí)候執(zhí)行。
  • 注意:這個(gè)下限時(shí)間有個(gè)范圍:[1, 2147483647],如果設(shè)定的時(shí)間不在這個(gè)范圍,將被設(shè)置為1。

I/O callbacks階段 這個(gè)階段執(zhí)行一些系統(tǒng)操作的回調(diào)。比如TCP錯(cuò)誤,如一個(gè)TCP socket在想要連接時(shí)收到ECONNREFUSED,
類unix系統(tǒng)會(huì)等待以報(bào)告錯(cuò)誤,這就會(huì)放到 I/O callbacks 階段的隊(duì)列執(zhí)行.
名字會(huì)讓人誤解為執(zhí)行I/O回調(diào)處理程序, 實(shí)際上I/O回調(diào)會(huì)由poll階段處理.

poll階段 poll 階段有兩個(gè)主要功能:(1)執(zhí)行下限時(shí)間已經(jīng)達(dá)到的timers的回調(diào),(2)然后處理 poll 隊(duì)列里的事件。
當(dāng)event loop進(jìn)入 poll 階段,并且 沒有設(shè)定的 timers(there are no timers scheduled),會(huì)發(fā)生下面兩件事之一:

  • 如果 poll 隊(duì)列不空,event loop會(huì)遍歷隊(duì)列并同步執(zhí)行回調(diào),直到隊(duì)列清空或執(zhí)行的回調(diào)數(shù)到達(dá)系統(tǒng)上限;

如果 poll 隊(duì)列為空,則發(fā)生以下兩件事之一:

  • 如果代碼已經(jīng)被setImmediate()設(shè)定了回調(diào), event loop將結(jié)束 poll 階段進(jìn)入 check 階段來執(zhí)行 check 隊(duì)列(里面的回調(diào) callback)。
  • 如果代碼沒有被setImmediate()設(shè)定回調(diào),event loop將阻塞在該階段等待回調(diào)被加入 poll 隊(duì)列,并立即執(zhí)行。

但是,當(dāng)event loop進(jìn)入 poll 階段,并且 有設(shè)定的timers,一旦 poll 隊(duì)列為空(poll 階段空閑狀態(tài)):

event loop將檢查timers,如果有1個(gè)或多個(gè)timers的下限時(shí)間已經(jīng)到達(dá),event loop將繞回 timers 階段,并執(zhí)行 timer 隊(duì)列。

check階段 這個(gè)階段允許在 poll 階段結(jié)束后立即執(zhí)行回調(diào)。如果 poll 階段空閑,并且有被setImmediate()設(shè)定的回調(diào),event loop會(huì)轉(zhuǎn)到 check 階段而不是繼續(xù)等待。

  • setImmediate() 實(shí)際上是一個(gè)特殊的timer,跑在event loop中一個(gè)獨(dú)立的階段。它使用libuv的API
    來設(shè)定在 poll 階段結(jié)束后立即執(zhí)行回調(diào)。
  • 通常上來講,隨著代碼執(zhí)行,event loop終將進(jìn)入 poll 階段,在這個(gè)階段等待 incoming connection, request 等等。但是,只要有被setImmediate()設(shè)定了回調(diào),一旦 poll 階段空閑,那么程序?qū)⒔Y(jié)束 poll 階段并進(jìn)入 check 階段,而不是繼續(xù)等待 poll 事件們 (poll events)。

close callbacks 階段 如果一個(gè) socket 或 handle 被突然關(guān)掉(比如 socket.destroy()),close事件將在這個(gè)階段被觸發(fā),否則將通過process.nextTick()觸發(fā)

這里呢,我們通過偽代碼來說明一下,這個(gè)流程:

// 事件循環(huán)本身相當(dāng)于一個(gè)死循環(huán),當(dāng)代碼開始執(zhí)行的時(shí)候,事件循環(huán)就已經(jīng)啟動(dòng)了
// 然后順序調(diào)用不同階段的方法
while(true){
// timer階段
    timer()
// I/O callbacks階段
    IO()
// idle階段
    IDLE()
// poll階段
    poll()
// check階段
    check()
// close階段
    close()
}
// 在一次循環(huán)中,當(dāng)事件循環(huán)進(jìn)入到某一階段,加入進(jìn)入到check階段,突然timer階段的事件就緒,也會(huì)等到當(dāng)前這次循環(huán)結(jié)束,再去執(zhí)行對應(yīng)的timer階段的回調(diào)函數(shù) 
// 下面看這里例子
const fs = require('fs')
// timers階段
const startTime = Date.now();
setTimeout(() => {
    const endTime = Date.now()
    console.log(`timers: ${endTime - startTime}`)
}, 1000)
// poll階段(等待新的事件出現(xiàn))
const readFileStart =  Date.now();
fs.readFile('./Demo.txt', (err, data) => {
    if (err) throw err
    let endTime = Date.now()
    // 獲取文件讀取的時(shí)間
    console.log(`read time: ${endTime - readFileStart}`)
    // 通過while循環(huán)將fs回調(diào)強(qiáng)制阻塞5000s
    while(endTime - readFileStart < 5000){
        endTime = Date.now()
    }
})
// check階段
setImmediate(() => {
    console.log('check階段')
})
/*控制臺(tái)打印check階段read time: 9timers: 5008通過上述結(jié)果進(jìn)行分析,1.代碼執(zhí)行到定時(shí)器setTimeOut,目前timers階段對應(yīng)的事件列表為空,在1000s后才會(huì)放入事件2.事件循環(huán)進(jìn)入到poll階段,開始不斷的輪詢監(jiān)聽事件3.fs模塊異步執(zhí)行,根據(jù)文件大小,可能執(zhí)行時(shí)間長短不同,這里我使用的小文件,事件大概在9s左右4.setImmediate執(zhí)行,poll階段暫時(shí)未監(jiān)測到事件,發(fā)現(xiàn)有setImmediate函數(shù),跳轉(zhuǎn)到check階段執(zhí)行check階段事件(打印check階段),第一次時(shí)間循環(huán)結(jié)束,開始下一輪事件循環(huán)5.因?yàn)闀r(shí)間仍未到定時(shí)器截止時(shí)間,所以事件循環(huán)有一次進(jìn)入到poll階段,進(jìn)行輪詢6.讀取文件完畢,fs產(chǎn)生了一個(gè)事件進(jìn)入到poll階段的事件隊(duì)列,此時(shí)事件隊(duì)列準(zhǔn)備執(zhí)行callback,所以會(huì)打?。╮ead time: 9),人工阻塞了5s,雖然此時(shí)timer定時(shí)器事件已經(jīng)被添加,但是因?yàn)檫@一階段的事件循環(huán)為完成,所以不會(huì)被執(zhí)行,(如果這里是死循環(huán),那么定時(shí)器代碼永遠(yuǎn)無法執(zhí)行)7.fs回調(diào)阻塞5s后,當(dāng)前事件循環(huán)結(jié)束,進(jìn)入到下一輪事件循環(huán),發(fā)現(xiàn)timer事件隊(duì)列有事件,所以開始執(zhí)行 打印timers: 5008ps:1.將定時(shí)器延遲時(shí)間改為5ms的時(shí)候,小于文件讀取時(shí)間,那么就會(huì)先監(jiān)聽到timers階段有事件進(jìn)入,從而進(jìn)入到timers階段執(zhí)行,執(zhí)行完畢繼續(xù)進(jìn)行事件循環(huán)check階段timers: 6read time: 50082.將定時(shí)器事件設(shè)置為0ms,會(huì)在進(jìn)入到poll階段的時(shí)候發(fā)現(xiàn)timers階段已經(jīng)有callback,那么會(huì)直接執(zhí)行,然后執(zhí)行完畢在下一階段循環(huán),執(zhí)行check階段,poll隊(duì)列的回調(diào)函數(shù)timers: 2check階段read time: 7 */

走進(jìn)案例解析

我們來看一個(gè)簡單的EventLoop的例子:

const fs = require('fs');
let counts = 0;
// 定義一個(gè) wait 方法
function wait (mstime) {
  let date = Date.now();
  while (Date.now() - date < mstime) {
    // do nothing
  }
}
// 讀取本地文件 操作IO
function asyncOperation (callback) {
  fs.readFile(__dirname + '/' + __filename, callback);
}
const lastTime = Date.now();
// setTimeout
setTimeout(() => {
  console.log('timers', Date.now() - lastTime + 'ms');
}, 0);
// process.nextTick
process.nextTick(() => {
  // 進(jìn)入event loop
  // timers階段之前執(zhí)行
  wait(20);
  asyncOperation(() => {
    console.log('poll');
  });  
});
/** * timers 21ms * poll */

這里呢,為了讓這個(gè)setTimeout優(yōu)先于fs.readFile 回調(diào), 執(zhí)行了process.nextTick, 表示在進(jìn)入timers階段前, 等待20ms后執(zhí)行文件讀取.

nextTick 與 setImmediate

  • process.nextTick 不屬于事件循環(huán)的任何一個(gè)階段,它屬于該階段與下階段之間的過渡, 即本階段執(zhí)行結(jié)束, 進(jìn)入下一個(gè)階段前, 所要執(zhí)行的回調(diào)。有給人一種插隊(duì)的感覺.
  • setImmediate 的回調(diào)處于check階段, 當(dāng)poll階段的隊(duì)列為空, 且check階段的事件隊(duì)列存在的時(shí)候,切換到check階段執(zhí)行,

nextTick 遞歸的危害

由于nextTick具有插隊(duì)的機(jī)制,nextTick的遞歸會(huì)讓事件循環(huán)機(jī)制無法進(jìn)入下一個(gè)階段. 導(dǎo)致I/O處理完成或者定時(shí)任務(wù)超時(shí)后仍然無法執(zhí)行, 導(dǎo)致了其它事件處理程序處于饑餓狀態(tài). 為了防止遞歸產(chǎn)生的問題, Node.js 提供了一個(gè) process.maxTickDepth (默認(rèn) 1000)。

const fs = require('fs');
let counts = 0;
function wait (mstime) {
  let date = Date.now();
  while (Date.now() - date < mstime) {
    // do nothing
  }
}
function nextTick () {
  process.nextTick(() => {
    wait(20);
    console.log('nextTick');
    nextTick();
  });
}
const lastTime = Date.now();
setTimeout(() => {
  console.log('timers', Date.now() - lastTime + 'ms');
}, 0);
nextTick();

此時(shí)永遠(yuǎn)無法跳到timer階段去執(zhí)行setTimeout里面的回調(diào)方法, 因?yàn)樵谶M(jìn)入timers階段前有不斷的nextTick插入執(zhí)行. 除非執(zhí)行了1000次到了執(zhí)行上限,所以上面這個(gè)案例會(huì)不斷地打印出nextTick字符串

setImmediate

如果在一個(gè)I/O周期內(nèi)進(jìn)行調(diào)度,setImmediate() 將始終在任何定時(shí)器(setTimeout、setInterval)之前執(zhí)行.

setTimeout 與 setImmediate

  • setImmediate()被設(shè)計(jì)在 poll 階段結(jié)束后立即執(zhí)行回調(diào);
  • setTimeout()被設(shè)計(jì)在指定下限時(shí)間到達(dá)后執(zhí)行回調(diào);

無 I/O 處理情況下:

setTimeout(function timeout () {
  console.log('timeout');
},0);
setImmediate(function immediate () {
  console.log('immediate');
});

執(zhí)行結(jié)果:

C:\Users\92809\Desktop\node_test>node test.js
timeout
immediate
C:\Users\92809\Desktop\node_test>node test.js
timeout
immediate
C:\Users\92809\Desktop\node_test>node test.js
timeout
immediate
C:\Users\92809\Desktop\node_test>node test.js
immediate
timeout

從結(jié)果,我們可以發(fā)現(xiàn),這里打印輸出出來的結(jié)果,并沒有什么固定的先后順序,偏向于隨機(jī),為什么會(huì)發(fā)生這樣的情況呢?

答:首先進(jìn)入的是timers階段,如果我們的機(jī)器性能一般,那么進(jìn)入timers階段,1ms已經(jīng)過去了 ==(setTimeout(fn, 0)等價(jià)于setTimeout(fn, 1))==,那么setTimeout的回調(diào)會(huì)首先執(zhí)行。

如果沒有到1ms,那么在timers階段的時(shí)候,下限時(shí)間沒到,setTimeout回調(diào)不執(zhí)行,事件循環(huán)來到了poll階段,這個(gè)時(shí)候隊(duì)列為空,于是往下繼續(xù),先執(zhí)行了setImmediate()的回調(diào)函數(shù),之后在下一個(gè)事件循環(huán)再執(zhí)行setTimemout的回調(diào)函數(shù)。

問題總結(jié):而我們在==執(zhí)行啟動(dòng)代碼==的時(shí)候,進(jìn)入timers的時(shí)間延遲其實(shí)是==隨機(jī)的==,并不是確定的,所以會(huì)出現(xiàn)兩個(gè)函數(shù)執(zhí)行順序隨機(jī)的情況。

那我們再來看一段代碼:

var fs = require('fs')
fs.readFile(__filename, () => {
    setTimeout(() => {
        console.log('timeout');
    }, 0);
    setImmediate(() => {
        console.log('immediate');
    });
});

打印結(jié)果如下:

C:\Users\92809\Desktop\node_test>node test.js
immediate
timeout

C:\Users\92809\Desktop\node_test>node test.js
immediate
timeout

C:\Users\92809\Desktop\node_test>node test.js
immediate
timeout

# ... 省略 n 多次使用 node test.js 命令 ,結(jié)果都輸出 immediate timeout

這里,為啥和上面的隨機(jī)timer不一致呢,我們來分析下原因:

原因如下:fs.readFile的回調(diào)是在poll階段執(zhí)行的,當(dāng)其回調(diào)執(zhí)行完畢之后,poll隊(duì)列為空,而setTimeout入了timers的隊(duì)列,此時(shí)有代碼 setImmediate(),于是事件循環(huán)先進(jìn)入check階段執(zhí)行回調(diào),之后在下一個(gè)事件循環(huán)再在timers階段中執(zhí)行回調(diào)。

當(dāng)然,下面的小案例同理:

setTimeout(() => {
    setImmediate(() => {
        console.log('setImmediate');
    });
    setTimeout(() => {
        console.log('setTimeout');
    }, 0);
}, 0);

以上的代碼在timers階段執(zhí)行外部的setTimeout回調(diào)后,內(nèi)層的setTimeoutsetImmediate入隊(duì),之后事件循環(huán)繼續(xù)往后面的階段走,走到poll階段的時(shí)候發(fā)現(xiàn)隊(duì)列為空,此時(shí)有代碼有setImmedate(),所以直接進(jìn)入check階段執(zhí)行響應(yīng)回調(diào)(==注意這里沒有去檢測timers隊(duì)列中是否有成員到達(dá)下限事件,因?yàn)閟etImmediate()優(yōu)先==)。之后在第二個(gè)事件循環(huán)的timers階段中再去執(zhí)行相應(yīng)的回調(diào)。

綜上所演示,我們可以總結(jié)如下:

  • 如果兩者都在主模塊中調(diào)用,那么執(zhí)行先后取決于進(jìn)程性能,也就是你的電腦好撇,當(dāng)然也就是隨機(jī)。
  • 如果兩者都不在主模塊調(diào)用(被一個(gè)異步操作包裹),那么setImmediate的回調(diào)永遠(yuǎn)先執(zhí)行。

nextTick 與 Promise

概念:對于這兩個(gè),我們可以把它們理解成一個(gè)微任務(wù)。也就是說,它其實(shí)不屬于事件循環(huán)的一部分。
那么他們是在什么時(shí)候執(zhí)行呢?
不管在什么地方調(diào)用,他們都會(huì)在其所處的事件循環(huán)最后,事件循環(huán)進(jìn)入下一個(gè)循環(huán)的階段前執(zhí)行。

setTimeout(() => {
    console.log('timeout0');
    new Promise((resolve, reject) => { resolve('resolved') }).then(res => console.log(res));
    new Promise((resolve, reject) => {
      setTimeout(()=>{
        resolve('timeout resolved')
      })
    }).then(res => console.log(res));
    process.nextTick(() => {
        console.log('nextTick1');
        process.nextTick(() => {
            console.log('nextTick2');
        });
    });
    process.nextTick(() => {
        console.log('nextTick3');
    });
    console.log('sync');
    setTimeout(() => {
        console.log('timeout2');
    }, 0);
}, 0);

控制臺(tái)打印如下:

C:\Users\92809\Desktop\node_test>node test.js
timeout0
sync
nextTick1
nextTick3
nextTick2
resolved
timeout2
timeout resolved

最總結(jié):timers階段執(zhí)行外層setTimeout的回調(diào),遇到同步代碼先執(zhí)行,也就有timeout0sync的輸出。遇到process.nextTickPromise后入微任務(wù)隊(duì)列,依次nextTick1、nextTick3nextTick2resolved入隊(duì)后出隊(duì)輸出。之后,在下一個(gè)事件循環(huán)的timers階段,執(zhí)行setTimeout回調(diào)輸出timeout2以及微任務(wù)Promise里面的setTimeout,輸出timeout resolved。(這里要說明的是 微任務(wù)nextTick優(yōu)先級(jí)要比Promise要高)

最后案例

代碼片段1:

setImmediate(function(){
  console.log("setImmediate");
  setImmediate(function(){
    console.log("嵌套setImmediate");
  });
  process.nextTick(function(){
    console.log("nextTick");
  })
});
/*     C:\Users\92809\Desktop\node_test&gt;node test.js    setImmediate    nextTick    嵌套setImmediate*/

解析:

事件循環(huán)check階段執(zhí)行回調(diào)函數(shù)輸出setImmediate,之后輸出nextTick。嵌套的setImmediate在下一個(gè)事件循環(huán)的check階段執(zhí)行回調(diào)輸出嵌套的setImmediate。

代碼片段2:

async function async1(){
    console.log('async1 start')
    await async2()
    console.log('async1 end')
  }
async function async2(){
    console.log('async2')
}
console.log('script start')
setTimeout(function(){
    console.log('setTimeout0') 
},0)  
setTimeout(function(){
    console.log('setTimeout3') 
},3)  
setImmediate(() => console.log('setImmediate'));
process.nextTick(() => console.log('nextTick'));
async1();
new Promise(function(resolve){
    console.log('promise1')
    resolve();
    console.log('promise2')
}).then(function(){
    console.log('promise3')
})
console.log('script end')

打印結(jié)果為:

C:\Users\92809\Desktop\node_test>node test.js
script start
async1 start
async2
promise1
promise2
script end
nextTick
promise3
async1 end
setTimeout0
setTimeout3
setImmediate

大家呢,可以先看著代碼,默默地在心底走一變代碼,然后對比輸出的結(jié)果,當(dāng)然最后三位,我個(gè)人認(rèn)為是有點(diǎn)問題的,畢竟在主模塊運(yùn)行,大家的答案,最后三位可能會(huì)有偏差;

以上就是Nodejs高并發(fā)原理示例詳解的詳細(xì)內(nèi)容,更多關(guān)于Nodejs高并發(fā)原理的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • mac下安裝node.js的詳細(xì)步驟

    mac下安裝node.js的詳細(xì)步驟

    Node.js本質(zhì)上是一個(gè)JavaScript運(yùn)行時(shí)環(huán)境,它提供了在服務(wù)器端運(yùn)行JavaScript代碼的能力,這篇文章主要給大家介紹了關(guān)于mac下安裝node.js的詳細(xì)步驟,需要的朋友可以參考下
    2023-10-10
  • 從零學(xué)習(xí)node.js之詳解異步控制工具async(八)

    從零學(xué)習(xí)node.js之詳解異步控制工具async(八)

    sync是一個(gè)流程控制工具包,提供了直接而強(qiáng)大的異步功能。基于JavaScript為Node.js設(shè)計(jì),同時(shí)也可以直接在瀏覽器中使用。下面這篇文章主要介紹了node.js之異步控制工具async的相關(guān)資料,需要的朋友可以參考下。
    2017-02-02
  • node版本管理工具n包使用教程詳解

    node版本管理工具n包使用教程詳解

    這篇文章主要介紹了node版本管理工具n包使用教程詳解,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-11-11
  • Nodejs中koa2連接mysql的實(shí)現(xiàn)示例

    Nodejs中koa2連接mysql的實(shí)現(xiàn)示例

    本文主要介紹了Nodejs中koa2連接mysql的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • node.js中的path.extname方法使用說明

    node.js中的path.extname方法使用說明

    這篇文章主要介紹了node.js中的path.extname方法使用說明,本文介紹了path.extname的方法說明、語法、使用實(shí)例和實(shí)現(xiàn)源碼,需要的朋友可以參考下
    2014-12-12
  • node.js中的console.warn方法使用說明

    node.js中的console.warn方法使用說明

    這篇文章主要介紹了node.js中的console.warn方法使用說明,本文介紹了console.warn的方法說明、語法、接收參數(shù)、使用實(shí)例和實(shí)現(xiàn)源碼,需要的朋友可以參考下
    2014-12-12
  • nodejs前端自動(dòng)化構(gòu)建環(huán)境的搭建

    nodejs前端自動(dòng)化構(gòu)建環(huán)境的搭建

    本文這里給大家介紹的是nodejs中前端自動(dòng)化構(gòu)建環(huán)境的搭建方法,非常的細(xì)致全面,有需要的小伙伴可以參考下
    2017-07-07
  • nodejs使用socket5進(jìn)行代理請求的實(shí)現(xiàn)

    nodejs使用socket5進(jìn)行代理請求的實(shí)現(xiàn)

    這篇文章主要介紹了nodejs使用socket5進(jìn)行代理請求的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • Node.js Buffer模塊功能及常用方法實(shí)例分析

    Node.js Buffer模塊功能及常用方法實(shí)例分析

    這篇文章主要介紹了Node.js Buffer模塊功能及常用方法,結(jié)合實(shí)例形式分析了Buffer模塊的各種常用函數(shù)及相關(guān)使用技巧,需要的朋友可以參考下
    2019-01-01
  • 淺談在node.js進(jìn)入文件目錄的問題

    淺談在node.js進(jìn)入文件目錄的問題

    今天小編就為大家分享一篇淺談在node.js進(jìn)入文件目錄的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05

最新評(píng)論