- PVSM.RU - https://www.pvsm.ru -

console.log не является частью JavaScript

Доброго времени суток, друзья!

Представляю вашему вниманию перевод заметки Nikhil John «console.log isn’t in the JavaScript language» [1].

Пожалуй, console.log является самой используемой командой в JS. Однако она не является частью JS. Не верите? А вы загляните в спецификацию ECMAScript2015 [2].

После того как я вас заинтриговал (потому что вы не обнаружили упоминания о console в ES6), позвольте мне продолжить.

То, что называют JS в браузере/на сервере, это лишь среда выполнения JS. Эта среда представляет собой так называемый «движок» JS (V8 в Chrome и NodeJS, SpiderMonkey в Firefox, JavaScriptCore в Safari).

Среда выполнения JS = движок JS (JS Runtime) + цикл событий (Event Loop) + внешние API + очередь функций обратного вызова (Callback Queue; далее — очередь).

Примечание: цикл событий, в зависимости от реализации, может входить в движок JS.

console.log не является частью JavaScript - 1

Объект console — это Web API, предоставляемый в распоряжение движка JS браузером, наряду с такими API, как DOM, Fetch, History, Service Workers и Web Storage. JS работает как в браузере, так и на сервере, и каждый из них имеет собственную реализацию console. Части JS, которые являются стандартными для всех сред выполнения, подробно описываются в спецификациях ECMA (речь идет о таких вещах, как «примитивы», типы данных, грамматика и синтаксис языка, арифметические и логические операции, встроенные объекты и функции и т.д.). Это означает, что одни вещи, такие как, например, Array.isArray(), встроены в JS, другие, такие как setTimeout(), нет.

Давайте посмотрим на реализации console в разных средах выполнения (сперва — Chrome v78, затем — Node v10, оба работают на V8):

console.log не является частью JavaScript - 2console.log не является частью JavaScript - 3

Реализация Node по сравнению с реализацией Chrome имеет парочку дополнительных методов (markTimeline, timeline, timelineEnd), хотя обе среды выполнения основаны на спецификации ECMA. Реализация console в Firefox также будет отличаться от представленных.

Почему это важно? Для того, чтобы понять, как работает JS, нужно знать, как язык взаимодействует со средой, в которую он встроен.

В действительности JS является однопоточным и синхронным языком.

Асинхронные операции (setTimeout, setInterval и др.) предоставляются и реализуются средой выполнения.

В браузере выполнение JS-кода имеет примерно следующий вид (спасибо Philip Roberts за Loop [3]). Обратите внимание, что JS или V8 — прямоугольник под названием «стек вызовов» (Call Stack) слева. Web API и очередь — компоненты среды выполнения браузера.
console.log не является частью JavaScript - 4

Это называется параллельной моделью выполнения событий или «Как однопоточный синхронный JS выполняет несколько (якобы) одновременных асинхронных операций». Это также объясняет ответ на популярный вопрос о том, почему код

console.log('Первый')

setTimeout(() => console.log('Второй'), 0)

console.log('Третий')

… выводит

Первый
Третий
Второй

… а не

Первый
Второй
Третий

JS выполняет каждую команду синхронно, одну за другой. Любой оператор с функцией обратного вызова (как, например, setTimeout) обрабатывается точно также, однако функция обратного вызова помещается в очередь.

Поскольку setTimeout — это Web API, он запускает внешний таймер в браузере вне среды выполнения JS. Может показаться, что JS выполняет «отложенный» код позже, но вот что происходит на самом деле:

  • ...
  • Цикл событий проверяет очередь (возвращает false; проверка осуществляется постоянно на предмет «непустоты», т.е. наличия чего-либо в очереди).
  • V8 берет setTimeout из стека вызовов и выполняет ее.
  • V8 получает уведомление о необходимости вызова Web API для запуска внешнего таймера (ВТ). ВТ запускается.
  • Цикл событий проверяет очередь (возвращает false).
  • V8 берет из стека вызовов следующую функцию и выполняет ее.
  • ...
  • ВТ заканчивается.
  • Web API помещает функцию обратного вызова (ФОВ) в очередь.
  • Цикл событий проверяет очередь (возвращает ФОВ).
  • Цикл событий помещает ФОВ в стек вызовов.
  • V8 берет ФОВ из стека вызовов и выполняет ее.
  • Цикл событий проверяет очередь (и ничего не возвращает).
  • ...

Вот и все, теперь мы знаем, как однопоточный синхронный JS выполняет асинхронные операции. Вся соль — во внешних API.

Счастливого кодинга!

Также см. серию статей [4] о том, как работает JS, от @ru_vds [5] и заметку «Парочка интересных методов объекта Console» [6].

Автор: aio350

Источник [7]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/javascript/347069

Ссылки в тексте:

[1] «console.log isn’t in the JavaScript language»: https://medium.com/swlh/console-log-isnt-in-the-javascript-language-2b0f24d57397

[2] ECMAScript2015: http://www.ecma-international.org/ecma-262/6.0/

[3] Loop: http://latentflip.com/loupe/?code=JC5vbignYnV0dG9uJywgJ2NsaWNrJywgZnVuY3Rpb24gb25DbGljaygpIHsKICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gdGltZXIoKSB7CiAgICAgICAgY29uc29sZS5sb2coJ1lvdSBjbGlja2VkIHRoZSBidXR0b24hJyk7ICAgIAogICAgfSwgMjAwMCk7Cn0pOwoKY29uc29sZS5sb2coIkhpISIpOwoKc2V0VGltZW91dChmdW5jdGlvbiB0aW1lb3V0KCkgewogICAgY29uc29sZS5sb2coIkNsaWNrIHRoZSBidXR0b24hIik7Cn0sIDUwMDApOwoKY29uc29sZS5sb2coIldlbGNvbWUgdG8gbG91cGUuIik7!!!PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D

[4] серию статей: https://habr.com/ru/company/ruvds/blog/337042/

[5] @ru_vds: https://habr.com/ru/users/ru_vds/

[6] «Парочка интересных методов объекта Console»: https://habr.com/ru/post/484544/

[7] Источник: https://habr.com/ru/post/488914/?utm_campaign=488914&utm_source=habrahabr&utm_medium=rss