Как V8 использует лучшее из обоих миров - JIT и интерпретатор

Помнить:

Мы анализируем код - ›Превращаем его в абстрактное синтаксическое дерево (AST). Интерпретатор (Ignition) - для двигателя V8 принимает этот AST и выдает байт-код (код не такого низкого уровня, как машинный код, но может быть интерпретирован движком для запуска программы).

Но затем, как вы можете видеть выше, есть профилировщик (Монитор) - этап 2. Этот монитор наблюдает за нашим кодом во время его выполнения и делает заметки о том, как его оптимизировать; например, он записывает, сколько раз он запускается.

Используя этот профилировщик, чтобы увидеть, как код выполняется в интерпретаторе, если одни и те же строки кода выполняются несколько раз, он передает этот код компилятору JIT для оптимизации.

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

Затем компилятор заменит разделы, которые могут быть улучшены в байтовом коде, на оптимизированный машинный код, чтобы с этого момента использовался оптимизированный машинный код вместо более медленного байтового кода.

Это смесь и совпадение, и это всегда цикл. Это означает, что скорость выполнения кода Javascript, который мы изначально вводили в движок, постепенно улучшается, поскольку профилировщик и компилятор будут вносить эти обновления и изменения в байтовый код, чтобы они были максимально эффективными.

Причина, по которой это важно знать, заключается в том, что теперь мы можем писать оптимизированный код - код, который компилятор может взять и запустить быстрее, чем обычный Javascript. Но мы также можем использовать эти знания, чтобы не сбивать компилятор с толку из-за его несовершенства; он может делать ошибки, когда пытается оптимизировать код. Код может сделать наоборот, и деоптимизация сделает наш код еще медленнее.

Написание оптимизаций

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

Вот основные вещи, которые следует помнить при работе с Javascript Engine. Эти случаи используются редко, но их полезно знать.

eval () // может быть проблематичным для оптимизации

arguments () // вместо этого лучше использовать деструктуризацию параметров.

for in () // при переходе по объектам. Вместо этого используйте object.keys для перебора ключей объекта.

с // проблемным

удалить // проблематично

Две основные причины, по которым вышеперечисленное может сделать наш код менее оптимизируемым:

1. Встроенное кеширование:

При встроенном кэшировании, когда компилятор видит код, который многократно выполняет один и тот же метод, допустим, что findUser () вызывается несколько раз, вместо того, чтобы каждый раз искать ключи объекта userData, он заменит его на 'Allan', 'Sendagi 'так что всякий раз, когда функция вызывается, мы просто "нашли Аллана Сендаги".

2. Скрытые классы
Что-то вроде ключевого слова delete будет мешать скрытым классам. Давайте посмотрим:

Приведенный выше код замедлит работу нашего компилятора, поскольку указанные выше свойства объекта не создаются в том же порядке. Скрытые классы, которые компилятор использует «под капотом» для определения того, что obj1 и obj2 имеют один и тот же скрытый класс, не будут выполнять эту оптимизацию.

Как только вы начнете представлять вещи в другом порядке, он запутается и придет к выводу, что у них разные скрытые классы. В результате будет сделан вывод, что это две разные вещи, и внутренне они будут замедлять процесс.

Ключ в том, чтобы писать код, который предсказуем как для людей, так и для машин. Чем более предсказуемым будет ваш код, тем он будет лучше - у вас не будет сюрпризов.

стек вызовов и куча памяти ›››