JS однопоточный
Самой большой особенностью языка JavaScript является однопоточность, но однопоточность здесь относится к тому, что основной поток является однопоточным. Так почему js однопоточный? Поскольку JS в основном используется для управления DOM, если есть два потока, один добавляет контент в DOM, а другой удаляет контент из DOM, какой из них должен выбрать браузер? Поэтому, чтобы избежать сложности, JavaScript с самого начала был однопоточным.
синхронный и асинхронный
Синхронный и асинхронный фокус на механизме уведомления о сообщениях
- 1) После вызова синхронизация не возвращается и результата нет.После возврата вызова получается возвращаемое значение. Вызывающий абонент будет активно ждать результата вызова.
- 2) Асинхронность заключается в том, что после совершения звонка вызывающий не получит результат сразу, а вызываемый обработает вызов через функцию состояния или обратного вызова.
очередь задач
- потому что
JavaScript
является однониточным. Это означает, что все задачи должны быть поставлены в очередь, и предыдущая задача завершается до того, как следующая задача может быть выполнена. Первая задача занимает много времени, а вторая задача должна ждать все время. Но устройства ввода-вывода (например,ajax
Сетевой запрос) очень медленный, а ЦП находится в состоянии первого дня, что очень неразумно. - Поэтому фактически основной поток может полностью игнорировать IO-устройство, приостановить ожидающую задачу и сначала запустить следующую задачу. Дождитесь, пока устройство ввода-вывода вернет результат, затем вернитесь и продолжите выполнение приостановленной задачи. Так что естьСинхронизировать задачуа такжеасинхронная задача.
同步任务
Это относится к задаче, выполняемой в основном потоке.Только после выполнения предыдущей задачи может быть выполнена следующая задача.异步任务
Это означает не вход в основной поток, а вход任务队列(task queue)
задача, выполняется только основная задача потока,очередь задачЗадача войдет в основной поток для выполнения.
Цикл событий в браузере
Смотрите на картинке выше:
- При запуске основного потока генерируются куча и стек
- Код в стеке вызывает различные внешние API, которые добавляют различные события (щелчок, загрузка, выполнение) в «очередь задач».
- Пока код выполняется в стеке, он будет основным потоком для чтения «Очереди задач», очереди событий в стек выполнения в последовательности.
- Основной поток продолжает выполняться, и когда внешний API вызывается снова, он добавляется в очередь задач.Когда основной поток завершит выполнение, он поместит события из очереди задач в основной поток.
- Весь описанный выше процесс цикличен.
Цикл событий узла
Node.js также является однопоточным циклом обработки событий, но его механизм работы отличается от среды браузера.
Согласно приведенному выше рисунку, механизм работы Node.js выглядит следующим образом:
- Написанный сценарий JavaScript будет передан движку V8 для анализа.
- После разбора кода вызовите Node API, и Node передаст егобиблиотека libuvиметь дело с
- библиотека libuvНазначайте разные задачи разным потокам для формирования цикла событий и возвращайте результаты выполнения задач в механизм V8 асинхронным образом.
- Затем движок V8 возвращает результат пользователю.
Кроме
setTimeout
а такжеsetInterval
Эти два метода Node.js также предоставляет два других метода, связанных с «очередью задач»:process.nextTickа такжеsetImmediate.
process.nextTick
Метод может вызвать функцию обратного вызова в конце текущего «стека выполнения» — перед следующим циклом событий (основной поток считывает «очередь задач»). То есть указанная задача всегда выполняется перед всеми асинхронными задачами.setImmediate
Метод заключается в добавлении события в конец текущей «очереди задач», то есть указанная им задача всегда выполняется в следующем цикле событий, что аналогичноsetTimeout(fn, 0)
Так же, как.
Английский оригинал:
When Node.js starts, it initializes the event loop, processes the provided input script (or drops into the REPL, which is not covered in this document) which may make async API calls, schedule timers, or call process.nextTick(), then begins processing the event loop.
Цикл событий инициализируется при запуске Node.js, и каждый цикл событий будет содержать шесть этапов цикла в следующем порядке.
┌───────────────────────┐
┌─>│ timers │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ I/O callbacks │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ idle, prepare │
│ └──────────┬────────────┘ ┌───────────────┐
│ ┌──────────┴────────────┐ │ incoming: │
│ │ poll │<─────┤ connections, │
│ └──────────┬────────────┘ │ data, etc. │
│ ┌──────────┴────────────┐ └───────────────┘
│ │ check │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
└──┤ close callbacks │
└───────────────────────┘
- этап таймеров:На этом этапе выполняется запланированный обратный вызов setTimeout (обратный вызов) и setInterval (обратный вызов);
- Этап обратных вызовов ввода/вывода:Выполнять обратные вызовы, отличные от обратных вызовов события закрытия, обратных вызовов, установленных таймерами (timers, setTimeout, setInterval и т. д.), и обратных вызовов, установленных setImmediate();
- бездействует, стадия подготовки:Используется только внутри узла;
- этап опроса:Получить новые события ввода-вывода, узел будет заблокирован здесь при соответствующих условиях;
- этап проверки:Выполнить обратные вызовы, установленные setImmediate();
- этап закрытия обратных вызовов:Например, на этом этапе будет выполнен обратный вызов socket.on('close', callback).
Каждый этап имеет очередь fifo (очередь), оснащенную обратными вызовами.Когда цикл событий доходит до указанного этапа, узел будет выполнять очередь fifo (очередь) этого этапа.Когда выполняется обратный вызов очереди или количество выполненных обратных вызовов превышает этап Когда будет достигнут верхний предел, цикл обработки событий перейдет к следующему этапу. **Обратите внимание, что ни один из шести вышеперечисленных этапов не включает process.nextTick(). **process.nextTick() не выполняется ни на одном этапе цикла обработки событий, а выполняется в середине каждого переключения этапов, то есть перед переключением с одного этапа на следующий.
Макрозадачи и микрозадачи
Задачи можно разделить на макрозадачи и микрозадачи
Общие макрозадачи и микрозадачи:
-
macro-task(宏任务)
:setTimeout
,setInterval
,setImmediate
,I/O
-
micro-task(微任务)
:process.nextTick
, РоднойPromise
(некоторые реализованыpromise
Будуthen
метод помещается в задачу макроса),Object.observe
(устаревший),MutationObserver
См. пример ниже:
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
Promise.resolve().then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
console.log('script end');
Каков порядок выполнения приведенного выше кода? Почему это?
script start
script end
promise1
promise2
setTimeout
Task
Он отправляется и выполняется в строгом хронологическом порядке, чтобы браузер могJavaScript
внутренние задачи иDOM
Задачи могут выполняться по порядку. Когда задача завершает выполнение, следующаяtask
Браузер может повторно отобразить страницу перед началом выполнения. Каждыйtask
Должны быть назначены, например, от кликов пользователя к событию клика, рендеринга HTML-документов, а также в приведенном выше примереsetTimeout
.
На основании ранее описанногоevent loop
,setTimeout
он выделит новый по истечении времени задержкиtask
кevent loop
вместо немедленного выполнения, поэтомуsetTimeout
Функция обратного вызова будет ждать завершения выполнения предыдущих задач перед запуском. поэтомуsetTimeout
Будет выводитьscript end
После этого, посколькуscript end
является частью первой задачи, иsetTimeout
это новыйtask
.
微任务
Обычно это требуетсяЗадача, которая будет выполняться сразу после завершения выполнения текущей задачиНапример, вам нужно ответить на ряд задач или вам нужно выполнять задачи асинхронно, не назначая новую задачу, что может снизить нагрузку на производительность.
Очередь задач микрозадач представляет собойtask
Очереди задач не зависят друг от друга, и микрозадачи будут выполняться в каждой очереди.task
Выполняется после завершения выполнения задачи. Каждыйtask
Микрозадачи, созданные в, будут добавлены в очередь микрозадач, микрозадачи, созданные в микрозадачах, будут добавлены в конец текущей очереди, а микрозадачи будут обрабатывать все задачи в очереди по порядку.
всякий раз, когдаPromise
Если она разрешена (или отклонена), ее функция обратного вызова будет добавлена в очередь микрозадач как новая микрозадача. Это также гарантируетPromise
Вы можете выполнить асинхронный. Итак, когда мы звоним.then(resolve, reject)
, новая микрозадача будет сгенерирована немедленно и добавлена в очередь, поэтому приведенное вышеpromise1
а такжеpromise2
будет выводиться вscript end
После этого, поскольку задачи в очереди микрозадач должны ждать текущегоtask
Выполнить после выполнения иpromise1
а такжеpromise2
вывод вsetTimeout
Раньше это было потому, чтоsetTimeout
это новыйtask
, а микрозадача выполняется в текущемtask
После окончания следующийtask
до начала.
Ссылаться на: