Как мы все знаем, наш JavaScript — это однопоточный язык Да, он также однопоточный, когда здесь Тяньван Лао-цзы, но задумывались ли вы когда-нибудь о том, почему JavaScript может выполнять функции во время выполнения таймеров, разве это не параллелизм?
1. Процессы и потоки
1.1 Процесс (Процесс)
Это работающая программа на компьютере с набором данных, базовая единица распределения ресурсов и планирования в системе, а также основа структуры операционной системы. В современных компьютерных архитектурах с поточно-ориентированным дизайном процессы являются контейнерами для потоков. Программа — это описание инструкций, данных и их организации, а процесс — сущность программы. Это работающая программа на компьютере с набором данных, базовая единица распределения ресурсов и планирования в системе, а также основа структуры операционной системы. Программа — это описание инструкций, данных и их организации, а процесс — сущность программы.
Здесь мы уподобляем процесс производственному цеху фабрики, который представляет собой единственную задачу, с которой может справиться центральный процессор. В любой момент ЦП всегда работает один процесс, а другие процессы находятся в неработающем состоянии.
1.2 Поток
Это наименьшая единица, которую операционная система может выполнять для планирования операций. Он содержится в процессе и является фактическим операционным блоком в процессе. Поток относится к одному последовательному потоку управления в процессе.Процесс может иметь несколько потоков одновременно, и каждый поток выполняет разные задачи параллельно.
Здесь поток уподобляется рабочим мастерской, то есть мастерская может позволить нескольким работникам сотрудничать для выполнения задачи.
2. Многопоточный браузер
я написал«Знания браузера, которые вы должны знать о фронтенд-разработке», вы можете посмотреть, когда у вас есть время.
Ядро браузера является многопоточным. Под управлением ядра каждый поток взаимодействует друг с другом для поддержания синхронизации. Браузер обычно состоит из следующих резидентных потоков:
- Поток рендеринга графического интерфейса
- Поток движка JavaScript
- поток триггера события
- синхронизированный триггерный поток
- Асинхронный поток HTTP-запросов
Мы видели поток движка JS, очень знакомый, в этом нет ничего плохого, здесь мы выполняем программу сценария javascript.
Механизм JS является многопоточным.Один поток означает, что когда механизм JS выполняет JS, для его выполнения выделяется только один поток, что означает, что механизм JS выделяет поток для выполнения JavaScript, что мы называем одним потоком. .
2.1 Давайте поговорим о механизме выполнения JS здесь
Поскольку JavaScript является однопоточным (в любое время существует только один поток JS, выполняющий программу JavaScript на странице вкладки).
Поэтому нам нужно полагаться на очередь задач для выполнения кода JavaScript.
Движок JS всегда будет ждать поступления задачи в очередь задач, а затем выполнять задачу.
Конечно, выполнять такие синхронные задачи не проблема, мы ставим все задачи в очередь задач и выполняем их одну за другой, и логика очень понятна. Однако, если мы отправим запрос в фон, время между отправкой и получением может занять секунду, разве мы не можем ждать его секунду, если он запрашивается пять раз, то ждать пять секунд? Отображение не соответствует нашим потребностям, поэтому для решения этой проблемы нам нужны асинхронные задачи.
2.2 Синхронные и асинхронные задачи
Синхронизировать задачуЭто относится к задачам, поставленным в очередь для выполнения в основном потоке. Только после завершения предыдущей задачи может быть выполнена следующая задача. Когда мы открываем веб-сайт, процесс рендеринга веб-сайта, такой как рендеринг элементов, на самом деле является синхронная задача.
асинхронная задачаЭто относится к задаче, которая не входит в основной поток, но входит в очередь задач.Только когда очередь задач информирует основной поток о том, что асинхронная задача может быть выполнена, задача входит в основной поток.Загрузка на самом деле является асинхронной задачей.
Каждый должен иметь более конкретное представление о цикле событий. Я не буду здесь вдаваться в подробности. Если вы не понимаете, вы можете сказать мне, и я просто расскажу об этом.
3. В этой статье основное внимание уделяется ключевым моментам — вы можете прочитать ее непосредственно
Но, ты прав?очередь задачЕсть вопросы? Это объект? это массив? По моей логике, наш основной поток JavaScript выполняет синхронные функции, а асинхронные функции можно поместить в очередь задач, которая может быть объектом, когда мы закончим выполнение синхронной задачи, мы запихиваем этот объект (очередь задач) в очередь задач. основной поток В этом потоке все в порядке, но это не то, что я думаю.
Очередь задач цикла событий размещается в браузере.поток триггера события, когда JS-движок выполняет асинхронную функцию, асинхронная задача будет помещена в поток, запускаемый событием. Когда соответствующая асинхронная задача удовлетворяет условиям запуска и запускается, поток, запускаемый событием, добавит асинхронную задачу в основной поток. движка JS. В конце очереди ожидает выполнения.
Отличается ли он от единого потока JavaScript, который мы себе представляем? Ну, это действительно не одно и то же, поэтому окончательный вывод заключается в том, что то, что мы называем очередью задач, оказывается потоком.
Затем, вернемся к таймеру, о котором мы упоминали в начале, каждый может догадаться, что он управляется потоком таймера.
Поскольку JavaScript является однопоточным, если он находится в состоянии заблокированного потока, это повлияет на точность синхронизации, поэтому необходимо открыть отдельный поток для синхронизации.
При использовании Settimeout или Setinterval это требует времени провода таймера, а конкретное событие будет нажато в очередь событий после завершения таймера.
4. Вывод
Итак, мы говорим, что JavaScript однопоточный, то есть он тоже однопоточный, когда здесь король, но наш Event Loop и таймер размещены в других потоках.
5. Двигатель V8 - удлинение
Движок V8 — это реализация движка JavaScript, первоначально разработанная некоторыми языковыми экспертами, а затем приобретенная Google, исходный код которого был затем открыт Google.
V8 разработан на C++. Перед запуском JavaScript V8 компилирует его в собственный машинный код (процессоры IA-32, x86-64, ARM или MIPS) по сравнению с другими механизмами JavaScript, которые преобразуют его в байт-код или интерпретируют его. И использует такие методы, как как встроенное кэширование для повышения производительности.
Благодаря этим функциям программы на JavaScript работают так же быстро, как бинарные программы под движком V8. V8 поддерживает многие операционные системы, такие как Windows, Linux, Android и т. д., а также другие аппаратные архитектуры, такие как IA32, X64, ARM и т. д., с хорошей переносимостью и кросс-платформенными функциями.
5.1 Рабочий процесс
В процессе выполнения JavaScript движок V8 в основном состоит из двух этапов: компиляции и выполнения.В отличие от полной компиляции перед выполнением C++, JavaScript необходимо компилировать и выполнять, когда пользователь его использует. В версии 8 код, связанный с JavaScript, не компилируется сразу весь, а только тогда, когда необходимо выполнить какой-то код, что улучшает время отклика и снижает затраты времени. В движке V8 исходный код сначала преобразуется синтаксическим анализатором в абстрактное синтаксическое дерево (AST), а затем собственный исполняемый код генерируется непосредственно из AST с помощью генератора полного кода JIT-компилятора. Этот процесс отличается от JAVA, который сначала генерирует байт-код или промежуточное представление, что сокращает время преобразования из AST в байт-код и повышает скорость выполнения кода. Но отсутствие промежуточного процесса преобразования в байт-код снижает возможность оптимизации кода.
Основные классы, используемые движком V8 при компиляции машинного кода, следующие:
- Сценарий: представляет код JavaScript, включая исходный код и локальный код, сгенерированный после компиляции, то есть запись компиляции и текущую запись;
- Компилятор: класс компилятора, класс вспомогательной группы Script для компиляции и генерации кода, вызов интерпретатора (парсера) для генерации AST и генератора полного кода, а также преобразования AST в собственный код;
- AstNode: класс узлов абстрактного синтаксического дерева, который является базовым классом всех остальных узлов, содержит множество подклассов, и позже для разных подклассов будут сгенерированы разные локальные коды;
- AstVisitor: класс посетителя абстрактного синтаксического дерева, который в основном используется для обхода разнородных абстрактных синтаксических деревьев;
- FullCodeGenerator: подкласс класса AstVisitor, который генерирует собственный исполняемый код для JavaScript путем обхода AST.
Процесс компиляции кода JavaScript примерно таков: класс Script вызывает функцию Compile класса Compiler, чтобы сгенерировать для него собственный код. Функция Compile сначала использует класс Parser для создания AST, а затем использует класс FullCodeGenerator для создания машинного кода. Собственный код тесно связан с конкретной аппаратной платформой, и FullCodeGenerator использует несколько серверных частей для создания собственного кода сборки, соответствующего платформе. Поскольку FullCodeGenerator генерирует соответствующий ассемблерный код для каждого узла путем обхода AST, глобальное представление отсутствует, и оптимизация между узлами невозможна.