2015-11-03 5 views
5

Я знаком с системами на основе событий в C++, а также с java. Я пытался изучить node.js и столкнулся с интересным поведением, и я надеялся, что кто-то сможет объяснить, что происходит под капотом.Если node.js однопоточный, то почему server.listen() возвращается?

У меня есть программа, которая выглядит как

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, а затем вернется и закроет программу.

Чтобы проверить это, я также добавил цикл занятости под консолью.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 сразу возвращается и затем застревает в замкнутом цикле, как ожидалось. Мой браузер не может подключиться к серверу, что ожидается.

Если я удалю цикл занятости и вернусь к исходному коду после console.log ('Main completed'); выполняется вместо выведенной программы, основной поток возвращается в цикл событий.

Как это работает. Почему основной поток возвращается обратно в код сервера после возврата основного потока?

Редактировать: Я думаю, что решено, что очередь событий не существует в основной функции, но где она? Что им это нужно? и когда основная функция запускается со ссылкой на нее?

+0

Полезно: http://blog.mixu.net/2011/02/01/understanding-the-node-js-event-loop/ – jarmod

+0

Я понимаю эту часть цикла событий. Мой вопрос касается того факта, что основной поток выходит и выглядит так, будто он перескакивает обратно в другую точку. – nbroeking

+0

потому что server.listen это асинхронная функция. Было бы неплохо прочитать о LivUV и EventEmmiter –

ответ

5

Представьте себе http.createServer(handler) и server.listen(port) как похожие на someElement.addEventListener('click', handler) в браузере.

При запуске someElement.addEventListener('click', handler), он связывает приемник событий, который будет отправлять handler в очереди обратного вызова, когда событие щелчка срабатывает на someElement.

http.createServer(handler) в сочетании с server.listen(port) работают очень похожим образом.http.createServer(handler) возвращает eventEmitter, а server.listen(port) сообщает node.js, что при получении HTTP-запроса на данном порту это событие должно быть запущено. Таким образом, когда приходит запрос, событие запускается, а handler помещается в очередь обратного вызова.

На данный момент это просто вопрос о том, как взаимодействует очередь вызовов и очередь обратного вызова. CallStack является в настоящее время выполняет стек функций, очередь обратного вызова представляет собой набор обратных вызовов, ожидающих быть выполнено, и цикл события является то, что тянет обратные вызовы от очереди обратного вызова и отправляет их в callstack.

Итак, в каком-то смысле цикл событий - это то, что делает все, что угодно, однако, если вы блокируете столбец от опорожнения, имея синхронный бесконечный цикл в одном из ваших обратных вызовов, цикл событий никогда не запускается снова, и обратные вызовы никогда не будут в результате чего было нарушено/не отвечает.

+0

Если вы все еще не совсем понимаете очередь событий/обратного вызова/callstack, смотрите это видео. https://www.youtube.com/watch?v=8aGhZQkoFbQ –

+0

Ваш ответ Помог много. Я не спрашиваю, как работает цикл событий. Это где больше? У меня создалось впечатление, что это было вслушиваться. Но теперь я понимаю, что это не так, но все равно должно быть где-то. Например, в java. Если вы собираетесь настроить очередь событий. Сначала вы создаете исполнителя, который действует как очередь событий, а затем нажимает на него события/runnables. Тот же принцип должен применяться к узлу. Эта очередь событий должна где-то существовать. Я просто пытаюсь понять, где это. – nbroeking

+1

То, как я это понимаю (возможно, я ошибаюсь ... сделаю дальнейшее исследование), заключается в том, что node.js реализует как очередь обратного вызова, так и цикл события, а не стоп-код. вы не контролируете его, все, что вы можете сделать, это повлиять на него, последовательно очистив стоп-вызов или заблокировав его. –

0

В основном http.createServer возвращает указатель на EventEmitter. Вы можете присоединить слушателей и т. Д. К объекту, который будет выполняться при испускании события. Они обрабатываются внутри цикла событий, который выполняется асинхронно и не блокирует основной поток. Оформить документацию HTTP для получения дополнительной информации о HTTP и EventEmitters.

+0

Если вызов асинхронный, то почему цикл занятости не позволяет обработать события? – nbroeking

+2

, потому что цикл занятости не позволяет обрабатывать все обратные вызовы; цикл события не может работать до тех пор, пока столбец не будет очищен. –

1

Основополагающая концепция для понимания здесь - это цикл событий и cooperative (non-preemptive) multitasking model.

Это server.listen Позволяет регистрировать обратный вызов с циклом события под ним и этот обратный вызов совместно использует основной поток выполнения с любым другим зарегистрированным обратным вызовом.

Когда вы бросаете, что занята петлю, то server.listen обратного вызова никогда не получает время выполнения (и ни один не делает двигатель событий, по этому вопросу), потому что система невытесняющего. То есть, никакой обратный вызов не может прервать любой другой - обратные вызовы должны отказаться от управления обратно в цикле событий путем завершения, после чего цикл события вызовет другие зарегистрированные обратные вызовы на основе событий, которые он поставил в очередь.

+0

Как известно конец функции, чтобы вернуться в цикл событий? – nbroeking

+0

Эта основная функция находится на более высоком уровне, чем цикл событий, который является частью самого движка. Когда основная функция запускается, цикл событий сидит неподвижно. Когда основная функция останавливается, начинается цикл события. Это характер узла: состояние «* цикл событий, прослушивание событий, без обратных вызовов» - это основное состояние узла. – kdbanman

+0

Я думаю, что понял. Основная функция сама по себе является обработанным событием? Итак, когда основная функция выполнена, она возвращается обратно в цикл событий, разрушающийся в движке? – nbroeking

Смежные вопросы