Среду выполнения(от англ. runtime - среда выполнения) и движки часто ошибочно называют одним и тем же.

Вы скорее всего слышали термины "движок JavaScript" и "среда выполнения JavaScript", которые используются, как взаимозаменяемые понятия, подразумевающие под собой "программу, которая выполняет JavaScript". Их часто смешивают, ссылаясь на V8, Node.js или некоторые другие комбинации схожих программ. Однако, существует значительная разница между движком и средой выполнения JavaScript с точки зрения их области применения и функциональности. Понимания этого различия является ключом к хорошему пониманию языка JavaScript в целом.

До обсуждения, что такое движок и среда выполнения, стоит определить несколько терминов, которые часто используются в связке как с движком, так и со средой выполнения: ECMAScript и JavaScript.

Что такое ECMAScript?

В 1996 году, компании Netscape и Sun Microsystems обратились к Ecma International, не коммерческой организации по стандартизации, для стандартизации JavaScript. Результатом этого сотрудничества стал релиз в 1997 году ECMA-262, спецификации, которая определяет как реализация JavaScript должна работать. Из-за нежелания компании Sun передавать торговую марку JavaScript спецификация существовала под другим именем, так ECMA-262 была переименована в "спецификацию языка ECMAScript". Таким образом ECMAScript - это имя языка объявленого в спецификации ECMA-262.

ECMAScript определяет основную функциональность JavaScript, которая должна быть реализована соответствующим образом независимо от места куда она встраивается(программа, которая встраивает реализацию, называется хостом(от англ. host - хост, хозяин)). Даже на этом раннем этапе компания Netscape уже намеревалась использовать JavaScript не только в браузере, но также и на сервере, и ECMAScript должен был являться основой для обеих реализаций. Сам по себе ECMAScript не содержит какой-либо веб-ориентированной функциональности, будь то информация ввода(от англ. input - ввод) или вывода(от англ. output - вывод), такая функциональность должна быть предоставлена хостом. Это означает, что ECMAScript содержит, к примеру, стандартные глобальные классы, такие как Object, Array и Promise, но не содержит HTMLElement, setTimeout или fetch().

Что такое JavaScript?

Хотя термин "JavaScript" не имеет формального определения, под ним обычно понимают дополненный язык ECMAScript. Это означает, что JavaScript реализовывает ECMAScript в дополнении к другим спецификациям и функциональности. В своей раннем форме JavaScript рассматривался, как ECMAScript + API на основе веб-технологий, например Объектная Модель Документа(DOM) и API, на основе браузерных технологий, таких как History API(пр. переводчика, History API предоставляет доступ к истории сеанса браузера через глобальный объект истории). Сегодня JavaScript рассматривается, как любая комбинация ECMAScript + любое API, предоставляемое хостом, включая веб-ориентированное API для браузеров и сервер-ориентированное API для хостов, таких как Node.js.

Что такое движок JavaScript?

То что в общем относят к движкам JavaScript может быть более точно названо движками ECMAScript, потому что они реализуют спецификацию ECMA-262 без почти какой-либо дополнительной функциональности. Движок JavaScript предназначается для встраивания на хост, который в свою очередь определяет дополнительную функциональность для ввода и вывода. Самые известные движки JavaScript следующие:

  • V8 - был создан как движок JavaScript для проекта Chromium, сейчас также используется в Node.js и Deno. Так как Edge и Opera основаны на Chromium, то можно по праву назвать V8 самым часто используемым движком JavaScript.

  • SpiderMonkey - движок JavaScript для Firefox.

  • JavaScriptCore - был создан как движок JavaScript для Safari, как в MacOS, так и в iOS, также используется в Bun.

Так как движки JavaScript реализуют только ECMAScript и должны расширяться за счет хоста, то они могут быть использованы в различных средах выполнения.

Что такое среда выполнения JavaScript?

Среда выполнения JavaScript - это хост ECMAScript, т.е. программа, которая встраивает движок JavaScript. Так Chrome, Firefox, Edge, Safari, Node.js, Deno и Bun - это все среды выполнения JavaScript, потому что они встраивают движок JavaScript и определяют дополнительную функциональность, которая доступна через JavaScript. Так веб-браузеры используют DOM и другое веб-API, в то время, как серверная среда выполнения осуществляет доступ к файловой системе.

Не существует каких-либо правил относительно того, какую дополнительную функциональность должна иметь среда выполнения JavaScript. Разработчики среды выполнения сами вправе решить этот вопрос. Вот почему Node.js, Deno и Bun все по разному реализуют работу с файловой системой и почему Deno решил отдать предпочтение веб-API такому как fetch(), в то время как Node.js изначально решил реализовать их собственный HTTP-клиент(с тех пор Node.js также адаптировал fetch()). Но не только API JavaScript делает среды выполнения JavaScript уникальными, но также и то, как именно они используют движок JavaScript.

Цикл событий(от англ. event loop - цикл событий) - это процесс, который позволяет среде выполнения переключаться между запуском JavaScript и выполнением других задач. Данный процесс не определен в ECMA-262 и никак не реализован в каком-либо движке JavaScript. Реализация собственного цикла событий отдается на откуп среде выполнения JavaScript. Веб-браузеры имеют собственную версию цикла событий, определенную в спецификации HTML, в то время как среды выполнения на стороне сервера, такие как Node.js, имеют свою версию данного процесса. Цикл событий не является обязательным для среды выполнения JavaScript, но он есть во всех универсальных средах выполнения JavaScript.

Подводя итог

Движки и среды выполнения JavaScript связаны, но тем не менее они разные. Движок JavaScript реализовывает ECMAScript согласно стандарту ECMA-262. Данный стандарт определяет основную функциональность JavaScript без какой-либо реализации ввода и вывода. Среда выполнения JavaScript - это хост ECMAScript, который встраивает движок JavaScript и дополняет его различной функциональностью для ввода и вывода наряду с тем, что еще нужно для самой среды выполнения. Дополнительная функциональность может включать в себя DOM в веб-браузере или доступ к файловой системе в серверных средах выполнения. Сами среды выполнения не имеют каких-либо обязательств для следования другим стандартам и вправе определять свое собственное необходимое им API, именно поэтому Node.js, Deno и Bun имеют разное API для работы с файловой системы.

Комментарии (14)


  1. me21
    20.04.2024 13:24

    Спасибо. Как могла бы выглядеть среда выполнения JavaScript без цикла событий?


    1. slonopotamus
      20.04.2024 13:24

      Точно так же как с циклом, только без цикла. Ничего принципиально не мешает реализовать его внутри самого приложения, если он нужен.


      1. gmtd
        20.04.2024 13:24

        А рендеринг и другие заприложенские вещи кто будет делать?


        1. slonopotamus
          20.04.2024 13:24
          +1

          Во-первых, про рендеринг в условии не было. В node.js нет рендеринга, например. Во-вторых, приложение может само делать рендеринг в своём цикле.


          1. gmtd
            20.04.2024 13:24

            Ну, хорошо

            Обычный промис с setTimeout или fetch вы как на чистом js реализуете?

            Или сам setTimeout


            1. andreymal
              20.04.2024 13:24

              Обе эти вещи тоже отсутствуют в спецификации ECMAScript

              Ну и обе эти вещи (да и рендеринг тоже) зависят от системных вызовов, так что задача сводится к созданию биндингов к интерфейсам операционной системы и всех интересующих обёрток над этими биндингами


              1. Alexandroppolus
                20.04.2024 13:24

                Но, кажется, сам по себе промис определен именно в спецификации языка. Т.е. среда выполнения обязана предоставить микротаски для колбэков then (обычные таски, которые "макро", на голом js создать не из чего, а вот зарезолвленный промис - вполне).


                1. andreymal
                  20.04.2024 13:24

                  А никаких микро-макро-тасков в спецификации тоже не видно, вместо них какие-то Jobs (возможно ли их реализовать поверх упомянутых мной биндингов — не проверял, но на первый взгляд почему бы и нет)


            1. slonopotamus
              20.04.2024 13:24

              Почему сразу "на чистом js"? У нас же среда выполнения.


            1. aamonster
              20.04.2024 13:24

              Он не реализуется на чистом js, говорю как человек, которому это понадобилось делать :-)

              Просто реализуете в нативе функцию SetTimeout, которая обеспечивает нужный функционал, и скармливаете её js-движку.


    1. unreal_undead2
      20.04.2024 13:24
      +1

      https://v8.dev/docs/d8 - просто исполнение кода в command line.


  1. bi_zi
    20.04.2024 13:24

    Возможно ли в теории реализовать многопоточность если разработчики движка и среды выполнения этого захотят?


    1. slonopotamus
      20.04.2024 13:24

      Почему бы и нет. https://github.com/koculu/Topaz


    1. ViktorVovk
      20.04.2024 13:24

      И не теоретически, а в спецификации давно все описано для реализации многопоточности. SharedArrayBuffer и Atomics, а там и мютексы и симафоры