Чтобы развивать способности, мы должны продолжать делать это постоянно, и мы должны всегда совершенствовать методы обучения и повышать эффективность обучения, чтобы добиться успеха. - Е Шэнтао
1. Почему мы используем узел и каковы его преимущества?
Основная цель Node — предоставить простой инструмент разработки для создания высокопроизводительных серверов. Также необходимо решить проблему с большим количеством одновременных пользовательских запросов к веб-серверу.
Решить высокий параллелизм?
Давайте возьмем пример здесь.Сравнение с нашей нодой и java, кто больше доминирует по одному и тому же запросу. посмотрите на картинку
- Когда количество пользовательских запросов увеличивается, node обрабатывает лучше, чем java.
并发
Производительность, он может быстро связывать события через основной поток. Java каждый раз создает поток, хотя теперь в Java есть线程池
Концепция может контролировать повторное использование и количество потоков. - Асинхронный ввод-вывод, узел может работать с базой данных быстрее. Java-доступ к базе данных столкнется с параллельной проблемой, вам нужно добавить концепцию блокировок. Здесь можно провести аналогию: после уроков идите к автомату с водой, чтобы набрать воду для питья.На Яве много людей, которые пьют воду сразу, и им нужно подождать.Узел подходит только к одному человеку, чтобы набрать воду на напитки за раз.
- Операции с интенсивным использованием ЦП относятся к операциям логической обработки, сжатию, распаковке, шифрованию и дешифрованию.Узел блокирует основной поток при выполнении операций с интенсивным использованием ЦП.
(单线程)
, время под ним не может быть быстро связано, поэтомуnode不适用于大型密集型CPU运算案例
, в то время как java хорошо подходит.
Node в веб-сценарии?
веб-конечная сцена в основном用户的请求
или读取静态资源
Что, очень подходит для разработки узла. Основные сценарии применения:聊天服务器
,电子商务网站
Дождитесь появления этих приложений с высокой степенью параллелизма.
2. Что такое узел?
Node.js — это JavaScript, основанный на движке Chrome V8.运行环境(runtime)
Узел не является языком, это то, чтобы JS пробег на бэкэнде运行时
, и не включает в себя полный набор javascript, потому что он не входит в состав сервераDOM
а такжеBOM
, Node также предоставляет некоторые новые модули, такие какhttp,fs
модули и т. д. Node.js использует事件驱动、非阻塞式 I/O
Модель, позволяющая сделать его легким и эффективным, и менеджер пакетов для Node.js.npm
, является крупнейшей в мире экосистемой библиотек с открытым исходным кодом.
Короче говоря, это просто среда выполнения, среда выполнения.
особенности узла
- Основной поток представляет собой одиночный поток (асинхронный), а последующая логика записывается в виде функции, которая передается в текущую выполняемую функцию.Когда выполняемая функция получает результат, выполняется переданная функция.
(回调函数)
. - Пять человек одновременно съедают тарелку риса (асинхронно).
- Блокировка не может быть асинхронной (теперь предположим, что база данных — это шеф-повар, официант — это узел, а клиент — запрос. Как правило, шеф-повар готовит и просит официанта передать его нескольким пользователям. Если шеф-повар приглашает официанта chat, это вызовет блокировку, и это для ядра).
- операции ввода-вывода, операции чтения и записи, асинхронное чтение и запись (вы можете использовать асинхронный, но не синхронный)
非阻塞式i/o
, который можно читать и записывать асинхронно. - event-driven
事件驱动
(опубликовать-подписаться).
Узловые процессы и потоки
进程
Это основная единица операционной системы для распределения ресурсов и планирования задач.线程
Это одноразовая рабочая единица программы, построенная на процессе, а процесс может иметь несколько потоков.
Перед этим давайте взглянем на механизм процесса браузера.
Сверху вниз они:
- Пользовательский интерфейс-- Включая адресную строку, меню закладок и т. д.
- браузерный движок--Передача инструкций между пользовательским интерфейсом и механизмом рендеринга (основной процесс браузера)
- движок рендеринга--Ядро браузера, например (webkit, Gecko)
- разное--Сетевой запрос, поток js и поток пользовательского интерфейса
С нашей точки зрения, нас больше заботит браузер.
渲染引擎
, посмотрим вниз.
движок рендеринга
- Механизм рендеринга
多线程
, включая поток пользовательского интерфейса и поток js. поток пользовательского интерфейса и поток js будутвзаимоисключающий, потому что результат выполнения потока js повлияет на поток пользовательского интерфейса, а обновление пользовательского интерфейса будет сохранено в очереди, пока поток js не будет бездействовать, он будет извлечен и обновлен. - JS однопоточный однопоточный, а почему? Если JS многопоточен, поэтому операция многопоточной DOM-операции, в этом случае будет оченьпутаница, DOM не знает кого слушать, а single thread здесь означает, что основной поток это single thread, он же может иметь и асинхронные потоки, и хранить эти потоки через очередь, но основной поток все равно одиночный поток , мы поговорим об этом позже. Таким образом, js также является однопоточным в node.
- Преимущество одиночного потока заключается в экономии памяти, отсутствии необходимости переключать контекст выполнения и не нужно беспокоиться о концепции блокировок, потому что мы передаем их каждый раз.
3. Цикл событий в браузере
Здесь я хочу сначала поговорить о цикле событий браузера Некоторые люди могут сказать, что ваша статья явно о том, как узел может быть связан с браузером. Во-первых, это разные среды выполнения с js в качестве основного языка, и у них есть сходство, кроме того, они не боятся задавать интервьюеру больше вопросов, если узнают больше. Ну, не буду нести чушь, давайте начнем.
Прежде всего, нам нужно знать взаимосвязь и значение кучи, стека и очереди.
- Куча: куча - это пространство для хранения объектов (объект, функция)
- Очередь (цикл): относится к хранению результатов всех асинхронных операций запроса, пока асинхронная операция не завершит свою миссию, событие будет добавлено в цикл,
队列是先进先出的
, как показано на рисунке ниже, самая продвинутая очередь будет воспроизводиться первой.
- Стек (стек): сам стек представляет собой переменную на основе хранилища, такую как 1, 2, 3 и ссылочные переменные.Некоторые люди здесь могут спросить вас, не является ли приведенная выше куча объектом ссылочного типа, и как изменить его на стек. Здесь я хочу объяснить, потому что хранится в стеке
引用变量
ссылается на ссылочный объект в кучеадрес,просто набор адресов. Здесь стек представляет собой стек выполнения, наш основной поток JS.栈是先进后出的
, первый в последний из эквивалентен чашкам с питьевой водой, мы наливаем воду, теоретически, вода, которую мы пьем, является последней в чашке с водой. Мы можем посмотреть на код,follow me.
function a(){
console.log('a')
function b(){
console.log('b')
function c(){
console.log('c')
}
c()
}
b()
}
a()
//这段代码是输出a,b,c,执行栈中的顺序的c,b,a,如果是遵循先进先出,就是输出c,b,a。所以栈先进后出这个特性大家要牢记。
Хорошо, теперь все знают взаимосвязь между кучей, стеком и очередью, а теперь давайте посмотрим на картинку.
я анализирую эту картинку
- Наши задачи синхронизации выполняются в основном потоке и формируют стек выполнения.
- Если вы столкнулись с асинхронными задачами, такими как
setTimeout、onClick
Дождитесь каких-то операций, результаты его выполнения мы поставим в очередь, а основной поток не будет блокироваться в этот период - Подождите, пока все задачи синхронизации в основном потоке будут выполнены, это пройдет
event loop
Возьмите его с начала в очереди и выполните его в стеке выполнения -
event loop
никогда не останавливаться - Весь процесс выше
Event Loop
(механизм цикла событий)
Микрозадачи, макрозадачи?
макрозадача: setTimeout, setImmediate, MessageChannel micro-task (микрозадача): родной промис (некоторые реализованные промисы помещают метод then в задачу макроса), Object.observe (устарело), MutationObserver
И микрозадачи, и макрозадачи являются асинхронными задачами, и все они относятся к очереди.Основное отличие заключается в порядке их выполнения, направлении и значении Event Loop. Так в чем же между ними разница?
Каждый раз, когда выполняется синхронная задача стека выполнения, завершенная асинхронная задача будет выниматься из очереди задач, а очередь делится наmicrotasks queues和宏任务队列
Подожди покаmicrotasks queues所有的microtasks
все выполнены, обратите внимание, что所有的
, он будет宏任务队列
Забрать событие. Подождите, пока событие не будет взято из очереди一个
, поставить в выполнение стек выполнения, даже конец цикла, тоevent loop
продолжит цикл, он снова пойдетmicrotasks queues
выполнить все задания до начала宏任务队列
принять внутрь一个
, и так далее.
- Задача синхронизации завершена
- выполнить
microtasks
, положить всеmicrotasks queues
пустой - выньте один
macrotasks queues
Событие завершения выполняется в стеке выполнения - идти выполнять
microtasks
- ...
- ...
- ...
Если я скажу это, все могут быть немного сбиты с толку, не паникуйте, давайте посмотрим на вопрос
setTimeout(()=>{
console.log('setTimeout1')
},0)
let p = new Promise((resolve,reject)=>{
console.log('Promise1')
resolve()
})
p.then(()=>{
console.log('Promise2')
})
Окончательный вывод: Promise1, Promise2, setTimeout1.
- Обещание1 в параметре обещания выполняется синхронно. Если вы не знаете много о обещаниях, пожалуйста, смотрите мою другую статью.Обещание: обещание, которое вы можете понять,
- Во-вторых, потому что обещания
microtasks
, перейдет к после выполнения задачи синхронизациипустойmicrotasks queues
, - Наконец, после очистки микрозадачи, перейдите кЗначение очереди задач макроса.
Promise.resolve().then(()=>{
console.log('Promise1')
setTimeout(()=>{
console.log('setTimeout2')
},0)
})
setTimeout(()=>{
console.log('setTimeout1')
Promise.resolve().then(()=>{
console.log('Promise2')
})
},0)
На этот раз он вложен, вы можете видеть, что окончательный вывод Promise1, setTimeout1, Promise2, setTimeout2
- После выполнения задачи синхронизации начального стека выполнения она перейдет к
microtasks queues
Находить - пустой
microtasks queues
, выходPromise1, и одновременно будет сгенерирована асинхронная задача setTimeout1 - идти
宏任务队列
Убедитесь, что очередь в это время установлена перед setTimeout1 перед setTimeout2, потому что setTimeout1 запускает асинхронное выполнение в начале стека выполнения, поэтому выводsetTimeout1, микрозадача Promise2 будет сгенерирована при выполнении setTimeout1, введитеmicrotasks queues
середина - Затем еще один цикл, чтобы очистить
microtasks queues
, выходPromise2 - пустой
microtasks queues
, он перейдет в очередь задач макроса, чтобы получить еще одну, на этот раз выборкаsetTimeout2
Четыре, узловые события в кольце
Цикл событий узла отличается от цикла браузера.Давайте сначала посмотрим на картинку, его рабочий процесс
- Сначала мы можем увидеть наш код js
(APPLICATION)
Сначала войдет двигатель v8, в основном в двигателе v8 есть некоторыеsetTimeout
такие методы, как. - Во-вторых, если в нашем коде выполняется nodeApi, например
require('fs').read()
, узел дастlibuv
Обработка библиотеки, этоlibuv
Библиотека написана кем-то другим, и он является кольцом событий узла. -
libuv
Как мы видим, библиотека обрабатывает события однопоточным асинхронным способом.work threads
представляет собой многопоточную очередь, через внешнююevent loop
Блокирующий способ выполнения асинхронных вызовов. - Подожди пока
work threads
Если в очереди есть событие, завершившее выполнение, оно будет пропущено черезEXECUTE CALLBACK
обратный вызовEVENT QUEUE
Очередь, ставь в очередь. - Наконец, в соответствии с событиями, выньте
EVENT QUEUE
Ставьте события в очередь, передайте их нашему приложению
цикл событий в узле
Цикл событий в узле находится в libuv.В libuv есть механизм цикла событий.Он инициализирует цикл событий при запуске узла.
- Каждому этапу здесь соответствуеточередь событий
- в любое время
event loop
При выполнении определенного этапа соответствующийочередь событийсобытия в , которые выполняются последовательно - Когда очередь выполняется или количество выполнений превышает верхний предел,
event loop
выполнит следующий этап - в любое время
event loop
При переключении очереди выполнения она будет очищенаmicrotasks queues
, а затем переключиться на следующую очередь для выполнения и т. д.
Здесь мы должны обратить вниманиеsetImmediate
Он принадлежит очереди проверки, а очередь опроса — это в основном асинхронные операции ввода-вывода, такие как fs.readFile() в узле.
Давайте подробнее рассмотрим, как он его использует.
setImmediate(()=>{
console.log('setImmediate1')
setTimeout(()=>{
console.log('setTimeout1')
},0)
})
setTimeout(()=>{
console.log('setTimeout2')
process.nextTick(()=>{console.log('nextTick1')})
setImmediate(()=>{
console.log('setImmediate2')
})
},0)
- Прежде всего, мы видим, что приведенный выше код выполняется первым.
setImmediate1
,В настоящее времяevent loop
существуетпроверить очередь - потом
setImmediate1
После удаления из очереди вывестиsetImmediate1
, то будетsetTimeout1
воплощать в жизнь - В настоящее время
event loop
законченныйпроверить очередьПосле этого начните движение вниз, и следующее выполнение будеточередь таймеров - Здесь будут проблемы, мы все знаем
setTimeout1
Если вы установите задержку на 0, все равно4msзадержка, то здесь будет два случая. Поговорим о первом, на этот разsetTimeout1
Это было реализовано- По правилам событийного цикла ноды мы будем выполнять все события, то есть выводитьочередь таймеровсередина
setTimeout2,setTimeout1
- В это время, в соответствии с правилом очереди «первым поступил — первым обслужен», порядок вывода следующий:
setTimeout2,setTimeout1
, после извлеченияsetTimeout2
, там будетprocess.nextTick
Выполнить (он будет помещен вочередь микрозадач), затем добавьтеsetImmediate
Выполнить (он будет помещен впроверить очередь) - В этот момент,
event loop
Пойдет, чтобы найти следующую очередь событий, в это времяevent loop
найдуочередь микрозадачЕсть событиеprocess.nextTick
, он будет очищать его, выводnextTick1
- наконец
event loop
Найти следующую очередь с событиемпроверить очередь,воплощать в жизньsetImmediate
, выходsetImmediate2
- По правилам событийного цикла ноды мы будем выполнять все события, то есть выводитьочередь таймеровсередина
- если здесь
setTimeout1
Он еще не был выполнен (4 мс задержали его пожизненное событие?)- В настоящее время
event loop
оказатьсяочередь таймеров, удалите *очередь таймеров**setTimeout2
, выходsetTimeout2
,Пучокprocess.nextTick
выполнить, тоsetImmediate
воплощать в жизнь - потом
event loop
Нужно найти следующую очередь событий,Здесь всем следует обратить вниманиеЗдесь произойдет 2 шага,1,setTimeout1
После завершения выполнения поместите его в очередь таймеров. 2. Найдите очередь микрозадач, которую нужно очистить., поэтому на этот раз он будет выведен первымnextTick1
- следующий
event loop
найдупроверить очередь,выньте казненный внутриsetImmediate2
- наконец
event loop
оказатьсяочередь таймеров, вынести казненногоsetTimeout1
.В этой ситуацииevent loop
еще один переключатель, чем указано выше
- В настоящее время
Так что есть два ответа
setImmediate1,setTimeout2,setTimeout1,nextTick1,setImmediate2
setImmediate1,setTimeout2,nextTick1,setImmediate2,setTimeout1
Рисунок здесь относится только к первому случаю, а другой случай аналогичен
Пять, синхронизация узлов, асинхронная, блокирующая, неблокирующая
- Синхронизация: то есть процесс вызывающего абонента ожидает вызываемого.Если вызываемый не возвращает результат, вызывающий всегда будет ждать.Это синхронизация.Синхронизация имеет возвращаемое значение
- Асинхронный: то есть вызывающий объект не ждет возврата вызываемого объекта, и вызываемый объект передаст статус, уведомление или функцию обратного вызова вызывающему объекту после выполнения.Async не имеет возвращаемого значения
- Блокировка: индекс текущего потока будет зависать до того, как будет возвращен результат, выполнение не будет продолжаться.
- Неблокирующий: то есть текущий поток будет продолжать выполняться независимо от того, что вы вернете
Некоторые люди могут испортить свои отношения,同步、异步
состояние вызываемого абонента,阻塞、非阻塞
это состояние, сообщение вызывающего абонента
Далее посмотрим, как будет выглядеть их комбинация
комбинация | значимость |
---|---|
синхронная блокировка | Это эквивалентно тому, что я иду в ресторан, чтобы поесть, и мне нужно подождать на кухне, пока еда будет приготовлена, прежде чем я смогу ее съесть. Я звонящий и мне нужно дождаться подачи блюда, поэтому я заблокирован.Блюдо приготовлено звонящим и напрямую мне дано синхронно |
Асинхронная блокировка | Я иду в ресторан, чтобы поесть, мне нужно дождаться, пока блюдо будет приготовлено, прежде чем есть, но у повара есть дела. Я надеюсь, что меня уведомят, чтобы забрать его после окончания работы. Как звонивший, ожидание заблокирован, а блюдо готово как вызываемый.Я буду уведомлен позже, так что это асинхронно, что в целом бесполезно. |
синхронный неблокирующий | Я пошел в ресторан поесть, сначала заказал тарелку горячих блюд, и ждал, пока повар приготовит на кухне, но я был очень голоден, поэтому я начал есть холодные блюда на кухне, я был звонившим, Я начал есть холодные блюда до того, как были готовы горячие блюда, неблокирующий, блюдо делается напрямую мне как вызываемому, синхронно, этот метод вообще бесполезен |
Асинхронный неблокирующий | Я иду в ресторан на ужин. Я заказал тарелку горячих блюд, повар готовит, но я очень голоден, я ем сначала холодные блюда, повар говорит мне принести их, когда они будут готовы, я звонящий, я не буду ждать горячих блюд быть приготовленным перед едой холодных блюд, да или нет блокировка блюда, так как вызываемый уведомляет меня, что get является асинхронным |
конец
Надеюсь, каждый что-то почерпнул из этой статьи, чтобы такого не было, когда вы пойдете на собеседование.
Скорее так. Ну, наконец, я надеюсь, что каждый сможет провести чемпионат мира по футболу.выиграть каждую ставку, ваша любимая команда также можетУбить финал.