搜尋

首頁  >  問答  >  主體

node.js - NodeJS异步机制的疑惑

问题描述:大家都知道nodejs因为其异步编程和事件机制而被大家津津乐道,但是最近在学习nodejs时对nodejs的异步不是很理解。都说nodejs是单进程单线程的,但是它的异步处理又给人的感觉是多线程的,比如下面的例子:

var fs = require("fs");

var data = fs.readFileSync('input.txt');//同步等待执行,这必然是单线程

console.log(data.toString());
console.log("程序执行结束!");

但是,它还有异步方式是这样处理:

var fs = require("fs");

fs.readFile('input.txt', function (err, data) {//异步执行,这个地方没有等待执行结束就已经打印了"程序执行结束",然后打印data数据
    if (err) return console.error(err);
    console.log(data.toString());
});

console.log("程序执行结束!");

希望大神们帮忙解释一下,总感觉它异步是多线程方式,而nodejs确实单进程单线程的?

PHP中文网PHP中文网2786 天前530

全部回覆(7)我來回復

  • 巴扎黑

    巴扎黑2017-04-17 16:14:59

    node是單線程的沒錯,可以把這個線程理解為主線程,當遇到異步時,會把文件讀取異步的任務交給底層的libuv,會根據平台選擇(文件IO採用線程池,網絡IO,linux採用epoll,windows採用IOCP)只是執行js程式碼的是單執行緒而已,非同步任務完成後會放進事件佇列,事件輪詢,等到主執行緒空閒時取出來處理。

    回覆
    0
  • 大家讲道理

    大家讲道理2017-04-17 16:14:59

    其實題主只要在網路上搜一下node event loop的機制就能明白node的非同步是怎麼運作的了。 node event loop的机制就能明白node的异步是怎么工作的了。
    node底层有一个叫做libuv的东西,它与c/c++做交互,比如I/O,网络请求等等。

    大概说下event loop的机制,题主最好网上搜下,深入理解下。

    比如你写的例子:

        1. var fs = require("fs");
    
        2. fs.readFile('input.txt', 4. function (err, data) {//异步执行,这个地方没有等待执行结束就已经打印了"程序执行结束",然后打印data数据
            if (err) return console.error(err);
            console.log(data.toString());
        });
        
        3. console.log("程序执行结束!");

    方便介绍,我标上了序号。它的工作机制大概是这样的:
    程序运行到 1 处。引用完之后继续走,到了2处,node发现是一个异步的I/O操作,总所周知I/O操作是巨费资源的,node是单线程它真的不想干这个事情,所以呢,它就交给了libuv,并给了它一个回调函数,也就是标4的那个地方,这个回调就是在c/c++底层处理完之后,libuv就会去调用这个回调。
    但在交给libuv的过程,程序是一直往下面运行的,也就到了3的地方,打印。
    这就是为什么先看到打印结果后看到文件内容。

    这也大概是Event Loop的工作机制,node一直把难搞的交给别人去搞,等别人搞完了,只执行一个回调而已。所以说node不适合做大量计算的工作,比如你写个while(true){}node底層有一個叫做libuv的東西,它與c/c++做交互,像是I/O,網路請求等等。

    大概說下event loop的機制,題主最好上網搜下,深入理解下。 🎜 🎜例如你寫的例子:🎜 rrreee 🎜方便介紹,我標上了序號。它的工作機制大概是這樣的:🎜程式運行到 1 處。引用完之後繼續走,到了2處,node發現是一個異步的I/O操作,總所周知I/O操作是巨費資源的,node是單線程它真的不想幹這個事情,所以呢,它就交給了libuv,並給了它一個回調函數,也就是標4的那個地方,這個回調就是在c/c++底層處理完之後,libuv就會去呼叫這個回呼。 🎜但在交給libuv的過程,程式是一直往下面運行的,也就到了3的地方,列印。 🎜這就是為什麼先看到列印結果後看到文件內容。 🎜 🎜這也大概是Event Loop的工作機制,node一直把難搞的交給別人去搞,等別人搞完了,只執行一個回調而已。所以說node不適合做大量計算的工作,像是你寫個while(true){}整個程式就蹦了。 🎜node就是喜歡小計算多並發,它處理起來真的有優勢,不服不行。 🎜

    回覆
    0
  • 怪我咯

    怪我咯2017-04-17 16:14:59

    我說下我的假設,
    假設讀取一個文件,NODEJS發送一個讀取信號(可能是發送其他什麼東西,原理一樣)給操作系統,此時NodeJS去幹別的事了(不用等待操作系統讀取檔案完畢,這就是非同步),作業系統讀取完畢後,發送一個事件給NodeJs,NodeJs就知道檔案讀取完畢,透過回呼函數回呼執行結果。
    讀取檔案的等待時間NodeJs拿來做別的事了,沒有阻塞。

    回覆
    0
  • 巴扎黑

    巴扎黑2017-04-17 16:14:59

    下面的那個如果等待讀取文件結束然後再打印下面的程序执行结束,那这和同步模式有啥区别吗…………
    nodejs是單線程的沒錯,這裡之所以下面的先打印出來了,因為是主進程結束之後再進行異步進程。

    回覆
    0
  • ringa_lee

    ringa_lee2017-04-17 16:14:59

    node是有事件隊列的

    回覆
    0
  • PHP中文网

    PHP中文网2017-04-17 16:14:59

    查下事件循環 event loop ,定時器裡的函數會被放在事件隊列裡, 會在下一個循環裡按在事件隊列裡放入的先後順序執行

    回覆
    0
  • PHP中文网

    PHP中文网2017-04-17 16:14:59

    node的引擎是單線程的沒錯 但是他底層調用的libuv不是啊 libuv在linux上網絡請求用的epoll 文件讀取是自己建了個線程池 在windows上面用的iocp

    回覆
    0
  • 取消回覆