[英]If node.js is single threaded then why does server.listen() return?
我熟悉c ++和java中基於事件的系統。 我試圖學習node.js並遇到有趣的行為,我希望有人可以解釋幕后發生的事情。
我有一個看起來像的程序
var http = require("http");
function main(){
// Console will print the message
console.log('Server running at http://127.0.0.1:8080/');
var server = http.createServer(function (request, response) {
// Send the HTTP header
// HTTP Status: 200 : OK
// Content Type: text/plain
response.writeHead(200, {'Content-Type': 'text/plain'});
// Send the response body as "Hello World"
response.end('Hello World\n');
});
server.listen(8080); //Why is this not blocking
console.log('Main completed');
//main loop here prevents other stuff from working
}
main();
在像java或c這樣的語言中我會期待兩件事。 server.listen都提供了一個事件循環,它會導致server.listen永遠不會返回。 或者server.listen生成一個新線程並在新線程中立即運行事件循環。 然后它將調用console.log,然后返回並關閉該程序。
為了測試這個,我還在console.log下面添加了一個繁忙的循環。
var http = require("http");
function main(){
// Console will print the message
console.log('Server running at http://127.0.0.1:8080/');
var server = http.createServer(function (request, response) {
// Send the HTTP header
// HTTP Status: 200 : OK
// Content Type: text/plain
response.writeHead(200, {'Content-Type': 'text/plain'});
// Send the response body as "Hello World"
response.end('Hello World\n');
});
server.listen(8080); //Why is this not blocking
console.log('Main completed');
while(true){
console.log('hi');
}
}
main();
Server.listen立即返回,然后按預期陷入繁忙循環。 我的瀏覽器無法連接到服務器,這是預期的。
如果我刪除busy循環並返回原始代碼,一旦console.log('Main completed'); 執行而不是程序退出,主線程跳回到事件循環。
這是如何運作的。 為什么主線程返回后主線程會跳回到服務器代碼中?
編輯:我認為重新解決了主要功能中不存在事件隊列但它在哪里? 擁有什么? 什么時候主函數會參考它運行?
將http.createServer(handler)
和server.listen(port)
視為與瀏覽器中的someElement.addEventListener('click', handler)
類似。
當您運行someElement.addEventListener('click', handler)
,它會綁定一個事件偵聽器,該事件偵聽器將在someElement
上觸發click事件時將handler
發送到回調隊列。
http.createServer(handler)
與server.listen(port)
http.createServer(handler)
結合使用的方式非常相似。 http.createServer(handler)
返回一個eventEmitter
,而server.listen(port)
告訴node.js,當在給定端口上收到http請求時,應觸發此事件。 因此,當請求進入時,事件被觸發, handler
被推送到回調隊列。
此時,事件循環callstack和回調隊列如何交互只是一個簡單的問題。 callstack是當前正在執行的函數堆棧, 回調隊列是等待執行的回調集合,而事件循環是將回調隊列的回調拉出並將它們發送到callstack 。
因此,從某種意義上說,事件循環是保持一切運行的原因,但是,如果通過在其中一個回調中阻塞callstack使其無法循環,則事件循環永遠不會再次運行並且回調永遠不會被執行,從而導致破碎/反應遲鈍的申請。
這里要理解的基本概念是事件循環和協作(非搶先)多任務模型 。
那個server.listen
調用在下面用事件循環注冊一個回調,並且該回調與每個其他注冊的回調共享主執行線程。
當您拋出忙循環時, server.listen
回調永遠不會獲得執行時間(事件引擎也不會),因為系統是非搶占式的 。 也就是說,沒有回調可以中斷任何其他回調 - 回調必須通過終止將控制權放回到事件循環,因此事件循環將根據它已排隊的事件調用其他已注冊的回調。
基本上http.createServer
指針返回到一EventEmitter
。 您可以將偵聽器等附加到將在發出事件時執行的對象。 這些是在事件循環內部處理的,它是異步運行的,不會阻塞主線程。 結帳的HTTP文檔,了解有關詳細信息, HTTP
和EventEmitters
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.