Базовое событие собеседования узла? Микрозадачи, макрозадачи? Возьми тебя в полет

Node.js Java JavaScript опрос

Чтобы развивать способности, мы должны продолжать делать это постоянно, и мы должны всегда совершенствовать методы обучения и повышать эффективность обучения, чтобы добиться успеха. - Е Шэнтао

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еще один переключатель, чем указано выше

Так что есть два ответа

  1. setImmediate1,setTimeout2,setTimeout1,nextTick1,setImmediate2
  2. setImmediate1,setTimeout2,nextTick1,setImmediate2,setTimeout1

Рисунок здесь относится только к первому случаю, а другой случай аналогичен

Пять, синхронизация узлов, асинхронная, блокирующая, неблокирующая

  • Синхронизация: то есть процесс вызывающего абонента ожидает вызываемого.Если вызываемый не возвращает результат, вызывающий всегда будет ждать.Это синхронизация.Синхронизация имеет возвращаемое значение
  • Асинхронный: то есть вызывающий объект не ждет возврата вызываемого объекта, и вызываемый объект передаст статус, уведомление или функцию обратного вызова вызывающему объекту после выполнения.Async не имеет возвращаемого значения
  • Блокировка: индекс текущего потока будет зависать до того, как будет возвращен результат, выполнение не будет продолжаться.
  • Неблокирующий: то есть текущий поток будет продолжать выполняться независимо от того, что вы вернете

Некоторые люди могут испортить свои отношения,同步、异步состояние вызываемого абонента,阻塞、非阻塞это состояние, сообщение вызывающего абонента

Далее посмотрим, как будет выглядеть их комбинация

комбинация значимость
синхронная блокировка Это эквивалентно тому, что я иду в ресторан, чтобы поесть, и мне нужно подождать на кухне, пока еда будет приготовлена, прежде чем я смогу ее съесть. Я звонящий и мне нужно дождаться подачи блюда, поэтому я заблокирован.Блюдо приготовлено звонящим и напрямую мне дано синхронно
Асинхронная блокировка Я иду в ресторан, чтобы поесть, мне нужно дождаться, пока блюдо будет приготовлено, прежде чем есть, но у повара есть дела. Я надеюсь, что меня уведомят, чтобы забрать его после окончания работы. Как звонивший, ожидание заблокирован, а блюдо готово как вызываемый.Я буду уведомлен позже, так что это асинхронно, что в целом бесполезно.
синхронный неблокирующий Я пошел в ресторан поесть, сначала заказал тарелку горячих блюд, и ждал, пока повар приготовит на кухне, но я был очень голоден, поэтому я начал есть холодные блюда на кухне, я был звонившим, Я начал есть холодные блюда до того, как были готовы горячие блюда, неблокирующий, блюдо делается напрямую мне как вызываемому, синхронно, этот метод вообще бесполезен
Асинхронный неблокирующий Я иду в ресторан на ужин. Я заказал тарелку горячих блюд, повар готовит, но я очень голоден, я ем сначала холодные блюда, повар говорит мне принести их, когда они будут готовы, я звонящий, я не буду ждать горячих блюд быть приготовленным перед едой холодных блюд, да или нет блокировка блюда, так как вызываемый уведомляет меня, что get является асинхронным

конец

Надеюсь, каждый что-то почерпнул из этой статьи, чтобы такого не было, когда вы пойдете на собеседование.

Скорее так. Ну, наконец, я надеюсь, что каждый сможет провести чемпионат мира по футболу.выиграть каждую ставку, ваша любимая команда также можетУбить финал.