Pull to refresh
32
1
Роман Максимов @Parker0

Веб разработчик с 2006. Frontend-эксперт, ментор.

Send message

В этой статье я писал про IC объектов. Если вы не оперируете объектом, то и IC тут не будет работать. По крайней мере в том варианте, который я описывал. Тут даже не особо важно, передаете вы объект аргументом, или получаете его из вышестоящего контекста или еще как. Что касается конкретно аргументов функции и их количества, тут есть отдельные механизмы оптимизации. Но это уже совсем другая история. Думаю, будет отдельная статья про это.

Наверное очень помогло ребятам разрабатывающем GC что javascript однопоточный

И да и нет. С одной стороны, не надо заботиться о синхронизации потоков. С другой, процесс нельзя полностью (или, хотя бы, какую-то существенную часть) разнести по потокам, как это сделано в некоторых других языках, и планировщику нужно отдельно думать о том как и когда собрать мусор. Отсюда и вся вот эта эвристика.

Как вы это сами разбирали по исходным кода или есть такого рода документация у Chrome?

Это внутренние механизмы Chromium. Документации нет. Внутри исходного кода есть несколько README с общими понятиями и концепциями. Какую-то информацию Google сам презентовал на конференциях, например, Memory Reducer и тесты эффективности сборки мусора (с использованием Memory Reducer и без него), были представлены на 37-ой ежегодной конференции ACM SIGPLAN в 2016-м году. Что-то можно узнать из блога V8.dev (в статье есть ссылки на посты). Но часть информации уже устарела (не вся, базовые концепции всё еще актуальны), поэтому единственный достоверный источник - это сами исходники и история комитов. Плюс, иногда в комитах можно найти изначальный Design Doc или ссылку на тред с обсуждением.

Не уверен, что понял вопрос правильно. Но JS-скрипт действительно может быть загружен после всех остальных элементов. Это не фича современных браузеров, так было всегда.

Если коротко, <script> тэг, по умолчанию грузится в синхронном режиме и блокирует построение Render Tree, пока не будет полностью загружен. Чтобы разблокировать рендеринг, раньше была практика размещать скрипты в конце body, после всех остальных элементов. Это позволяло браузеру загрузить весь статический контент до начала обработки JS.

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

Режим async говорит браузеру, что скрипт должен грузиться асинхронно, т.е. он не будет блокировать основной поток и будет поставлен на исполнение по факту своей загрузки. По умолчанию, скрипты имеют значение async=false. Для включания асинхронного режима нужно указать атрибут <script src="..." async> (src у такого скрипта обязателен, если src не указан, async не будет иметь эффекта). Если скрипт был добавлен в DOM динамически, например, создан через document.createElement, он, по умолчанию будет иметь async=true, но его можно переопределить вручную (script.setAttribute("async", false)).

Атрибут defer оставляет загрузку скрипт в синхронном режиме, но ставит его в конец очереди, после всех остальных элементов. Если на странице есть несколько defered скриптов, они будут поставлены в очередь в том порядке, в котором были встречены парсером.

Почему сразу "опускаться"? В текущих реалиях, гос. сектор, как раз, набирает обороты. Цифр у меня нет, но здесь сейчас порядка 20% всей отечественной разработки. А с запуском ГосМаркета и СберЭкоСистемы (или как там её) будет около 30%

Вообще, гос. сектор я привел только как пример. По мимо него есть еще много чего специфического, например, тендерные площадки и аукционы, некоторый финтех, юридические и консалтинговые проекты, работающие с ЭЦП, и т.д.

Лозунг: "Все на ES6+" - это хорошо, но пока еще не наша реальность, к сожалению...

Не причина - согласен. Но ставят es5, еще как ставят. У будут ставить еще какое-то время. Например, в гос. проектах это, фактически, требование. Хоть в гос. секторе и разрешили Спутник (а местами, даже Яндекс-браузер), но по инерции, IE там еще вовсю используется.

По примерным подсчетам, на просторах сети сейчас порядка 5 млн. ресурсов, исторически использующих babel с целью транспиляции в es5. Эти ресурсы сетапились много лет назад и большинство из них, в ближайшие годы не перейдут на es6 без важной, на то, для этого конкретного проекта, причины. И проекты эти - не гугл.

В статье, в каждом конкретном случае написано, где "безопаснее" и зависит от того, что для вас является критерием безопасности, защита от ошибок разработки или от внешнего воздействия в проде.

Как связана статистика поддерживаемости es6 браузерами с тем фактом, что миллионы веб-ресурсов транспилируют свой код в es5 (включая такие компании, как Google, Яндекс, Facebook и др.)?

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

А вообще, статья задумывалась, как отправная точка в серии статей о реакте, где я планирую рассмотреть отдельные процессы более подробно.

Статья, в оригинале, действительно писался не для Хабра. Мотивацией к написанию послужило то, что я постоянно слышу от разработчиков, что typeof смотрит на первые три бита значения переменной и по ним определяет тип. Так было много лет назад, но давно уже ушло в историю. И V8, и SpiderMonkey сейчас построены совершенно по другому, и я посчитал нужным этот вопрос освятить. На Хабр пост попал только потому, что мне показалось, он здесь уместен и будет интересен сообществу. Все ссылки в тексте статьи, которые, в изначальном варианте, ведут на оригинальные публикации (не на Хабре) были заменены на кросс-статьи на Хабре, кроме стандартной, для моих публикаций, подписи в конце статьи.

Печально, что вы увидели в посте только рекламу и никакой полезной информации.

Я не говорил, что это прописано в спеке. Это скорее вопрос последующих дискуссий. Он лежит даже за пределами JS. Сам proposal был сделан на основе аналогий с другими ЯП (конкретно, за пример брался С++), со всеми вытекающими тредами по этой теме.

Формальную мотивацию можно посмотреть в ESLint https://eslint.org/docs/latest/rules/no-var#examples

Кому что проще понимать - вопрос сугубо индивидуальный. Я лишь попытался объяснить работы конкретно V8, а не абстрактного документа. Именно под V8 каждый день исполняется 65-75% всего JS. На мой взгляд, логично рассматривать работу JS именно на движке. Аналогично, если у вас ломается двигатель автомобиля, вы ищете проблему конкретно в вашем автомобиле, а не в ГОСТе по двигателям внутреннего сгорания (ГОСТ 10150-2014, кстати). Однако, еще раз, каждому свое, если спецификация вам удобнее/роднее для восприятия, это имеет место быть.

А вот тезис, что var был бы безопаснее ("гораздо"?) - извините, не выдерживает критики. Var, в данном случае, "всплывет" в глобальный scope (да, я в курсе, что в спецификации нет понятия "всплытие", но тем не менее), что дает возможность её последующей мутации за пределами switch. Более того, мутация произойдет прямо в вашем примере в блоке case "b", что может оказать явный или неявный сайд-эффект в блоке case "a" или в другом, пока неопределенном месте. Не просто так, с релизом ES6, var не рекомендуется к использованию вообще.

Не понял, при чем тут спецификация? Я писал про реализацию на конкретном движке, а не про спецификацию.

Судите сами:

Автор материала не знает, что Mozilla Developer Network никогда не являлась официальной документацией. Единственным официальным источником, с 1998 года является сайт спецификации ECMAScript.

Помоему, вы путаете документацию и спецификацию. Я уже отвечал на этот вопрос и в статье есть отсылки и к спецификации. Спецификация - документ, который пишет еще до каких либо разработок, а документация - после. Можно провести грубую аналогию с ГОСТом и инструкцией к конкретному продукту. Разве это один и тот же документ?

Дабы заркыть недопонимание, изменил формулировку в статье.

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

Может и должен. Однако, учат, в том числе в ВУЗах. Как учить языку, по спецификации, или по каким-то другим источникам - вопрос отдельный, и точно лежит за рамками этой дискуссии.

Сама по себе реализация стандарта, то есть тот самый код который обслуживает спецификацию - безусловно может быть разной. Но верхом глупости будет думать, что подобные реализации не соответствуют заявленной ими спецификации.

Где в статье говорится, что реализация не соответствует спецификации? Покажите, я исправлю. Наоборот, я говорю следующее

В целом, понятия "примитив" и "объект" в JavaScript были и остаются такими, как они были заложены в спецификации. Но во время работы с типами данных следует понимать, что понятия эти, скорее логические, нежели физические. Физическая реализация того или иного типа на уровне движка может отличаться и иметь индивидуальные особенности. 

Все последующие ваши цитаты и комментарии к ним, опять же, про спецификацию, которая в статье не рассматривается, а EventLoop и GarbageCollector вообще не упоминаются. При чем тут это всё?




По моему, практический смысл очевиден. Многие разработчики хотя бы раз слышали на интервью вопрос: "что такое область видимости?", однако, очень часто, интервьюер сам не может дать исчерпывающий ответ на этот вопрос. Как правило, область видимости считают ограниченной операторными скобками, что порождает ряд логичных вопросов.

Например:

- почему тогда for (let i, ...) оказывается замкнута в скоупе


- какого тип переменная "e" в конструкции catch (e)

- есть ли разница между

switch (a) {
case "":
const b = "b";
break;
}

и

switch (a) {
case "": {
const b = "b";
break;
}
}

- и т.д.

Я писал больше про HTML. HTTP тут упоминается вскользь. Период с 1990-х по н.в. я планирую описать в следующей статье.

Вот здесь не соглашусь. Что быстрее, вопрос очень спорный, истину может показать только эмпирический замер. Но, самое главное, производительность сценария - это не только скорость бинарных вычислений и кол-во переходов по указателям. На практике есть еще память, связанные процессы и GC, в конце концов. Как бы там ни было, true/false лежат в памяти всегда, вне зависимости от того, будут они использованы в коде или нет, их наличие не надо проверять, их не требуется записывать, они не обрабатываются GC.

Даже интересно стало замерить цифры. Думаю, есть смысл провести эксперимент и посмотреть.

Вопрос терминологии. Я, все таки, считаю, что "документация" и "спецификация" - не одно и то же. Спецификацию пишут до имплементации продукта/фичи в жизнь. Документация же - инструкция к тому, что получилось в итоге. Если говорить про спецификацию, да, первоисточник tc39, у меня есть отсылки к ней. Но вот в плане документации, более полной и "централизованной", чем MDN, я не знаю.

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

"Практический выхлоп" в том, чтобы понимать механизмы, которые работаю под капотом JS. Опытный водитель, зная, как устроен его автомобиль, в критической ситуации может не допустить поломку или починить, если что-то случилось в дороге. Так же и опытный разработчик, зная, как устроен движок/интерпретатор/компилятор, может, например, найти и устранить утечку памяти и, в целом, не будет заблуждаться на счет элементарных вещей. Например, некоторые разработчики (особенно пришедшие из Backend или под их вилянием) полагают, что использовать 1|0 вместо true|false - оптимальнее. Хотя, как мы видим, в JS это не совсем так, хоть разница в производительности и не велика. И таких кейсов можно набрать много. Дьявол, как говорится, кроется в деталях.

Статья было про типы данных. Бинарную арифметику я затрагивал. Но, если уже поднимать этот вопрос, быстрый ответ, потому что бинарная сумма 0.1+0.2 = 0.30000000000000004. Почему так происходит, думаю, в сети найдется много материала на этот счет. Если коротко, при суммировании двух чисел с плавающей точкой их мантиссы суммируются бинарным способом и иногда, вместо 52-битного слова, может получиться 53-битное. Соответственно, для приведения к 52 битам, результат нужно округлить. Более того, если у двух чисел разные экспоненты, вторая сдвигается относительно первой, что тоже может привести к переполнению разряда, тогда их тоже надо округлять. Отсюда и неточности в вычислении.

Не путаю, так уж решили разработчики V8. Сделано это было еще в 2009-м Эриком Корри для ускорения бинарных операций на архитектуре ARM. Суть как раз в том, чтобы делать их в обход FPU или эмуляторов (см коммит https://codereview.chromium.org/119241). Видимо, в 2009 на ARM это было актуально. Сам я в эту сторону далеко не копал.

1

Information

Rating
1,433-rd
Location
Санкт-Петербург, Санкт-Петербург и область, Россия
Date of birth
Registered
Activity

Specialization

Frontend Developer
Lead
From 8,000 $
JavaScript
TypeScript
React
HTML
CSS
Webpack
Redux
MobX