Бобров Максим Юрьевич @demimurych
FAEBFE; Тех SEO аудит. 90+ WebVitals etc…
Information
- Rating
- 5,109-th
- Location
- Харьков, Харьковская обл., Украина
- Date of birth
- Registered
- Activity
Specialization
Pentester, Reverse Engineer
Lead
FAEBFE; Тех SEO аудит. 90+ WebVitals etc…
Я не могу и не имею права спорить с автором материала.
Но очень хочу спросить - дети в той же британии тоже учат грамматику чтобы говорить на английском?
Или там какой-то иной принцип?
а еще можно было прочитать спецификацию html5 и узнать из нее, что атрибут lang может и обязан ставиться на каждый фразовый контент в случае если страница мультиязычная.
после чего убедиться что google, строго в соответствии со стандартом интерпретирует подобное поведение стандарта
Автор материала, далеко не всегда перепроверял себя, на соответствие заявленного им, официальному источнику.
Как следствие, почти все о чем идет речь в материале, представляет из себя винегрет из того, что действительно имеет отношение к официальной спецификации языка JavaScript помноженной на заблуждения автора.
Судите сами:
Автор материала не знает, что Mozilla Developer Network никогда не являлась официальной документацией. Единственным официальным источником, с 1998 года является сайт спецификации ECMAScript.
Кто Вас и тем более Всех этому учил, должен краснеть на месте. Потому, что согласно официальной спецификации языка JavaScript, никаких примитивных и тем более ссылочных типов - нет.
Даже если учесть общепринятый жаргон, относительно примитивных типов, то и в его рамках - никаких примитивных типов в языке JavaScript так же не существует. Потому как поведение тех типов, которые по умолчанию возвращают Primitive Value не укладываются в типичный набор критериев распространяемых в общем случае, на примитивные типы.
Главный из которых - строгая детерминированность поведения типа, вне зависимости от особенностей его использования.
То есть примитивный тип - это тип, который должен себя вести везде одинаково. При всех обстоятельствах. Чего в JavaScript нет.
Сама по себе реализация стандарта, то есть тот самый код который обслуживает спецификацию - безусловно может быть разной. Но верхом глупости будет думать, что подобные реализации не соответствуют заявленной ими спецификации.
То что написал автор - не имеет никакого отношения к официальной спецификации. Согласно которой, никаких примитивных типов в языке JavaScript не существует. Такого термина просто нет в официальной спецификации. Не говоря уже о том, что поведение выше заявленных типов, не отвечает общепринятому определению примитивных типов.
Согласно официальной спецификации абсолютно все типы в языке JavaScript являются ссылочными:
Это фундаментальная основа языка JavaScript которая закреплена на уровне главы формирующей операции используемый спецификацией.
Все алгоритмы спецификации, если явным образом не указано другого, описывают Expression или Statement в рамках заявленного в главе Algorithm Conventions алгоритма - а именно ссылочного типа.
Если быть максимальным занудой, то в академической среде, где работа с типами определяется как: By Value, By Reference и By Shared, работа со всеми типами в JavaScript отвечает термину By Shared. Что по сути своей является тем же ссылочным типом, и отличается только способом передачи в целевой индентификатор самой ссылки.
Иными словами - любые утверждения со стороны о том, что в языке JavaScript есть якобы типы, которые якобы примитивные противоречат как официальной спецификации, так и общепринятому жаргону.
Исключением являются типы связанные с TypedArray.
Object как тип, ничем не отличается от прочих типов языка JavaScript с точки зрения его описания. Но отличается тем что возвращается по умолчанию при запросе к идентификатору который с ним связан. В случае Object - возвращается структура типа. В случае типов, неправильно названных автором примитивными, по умолчанию возвращается primitive value. Чего не достаточно чтобы считать тип примитивным.
Ничего подобного не происходит. Это фантазии автора материала. Структура Object ничем не отличается по своему поведению от структуры Record в рамках которой описываются идентификаторы которые связывают с типами вида String, Number etc...
Как в первом так и во втором случае, работа происходит абсолютно идентичным образом, что зафиксировано официальной спецификацией.
Официальная спецификации - никак не управляет тем что будет с обьектом или еще чем-то.
Официальная спецификация никаким образом не заявляет поведение Garbage Collector-а или любой другой машинерии про то же самое.
Это все лежит на плечах, конкретного RunTime, работа которого ВООБЩЕ не зависит от того, будет ли уничтожен какой-то обьект на который нет ссылки или не будет.
Больше того, если уж мы говорим о V8, то в его рамках, Garbage Collector, сто раз подумает прежде чем удалять что -то из памяти даже если на это что-то 100500 раз нет никаких ссылок. По одной простой причине - если память есть и ее достаточно, то последнее что нужно делать, это заниматься чисткой чего-то на что нет ссылок. Особенно в контексте того, что то, что потеряло ссылку, буквально завтра может ее снова обрести. А процесс заведения нового обьекта не в пример дороже чем работа Garbage Collecotr-а.
Нет. Согласно официальной документации, представление типа Number может радикальным образом отличаться в зависимости от выражения в котором числовой литерал используется. И может быть действительно как число с плавающей точкой для выражения деления числа.
Одновременно с чем, оно может быть 32-битовым целым со знаком в рамках бинарных операций например and. При этом уничтожая всю метаинформацию о том, какая дробная часть (мантисса) было до этого.
Но и это далеко не все. В рамках спецификации, для сдвигов числовой литерал в выражении может становиться 32 битовым целым БЕЗ знака.
И все это, подчеркиваю, в рамках официальной спецификации.
(Передаем привет секте примитивных типов в JavaScript)
Еще как представляется.
То, что увидел автор материала, является частью поведения оптимизирующего алгоритма современного RunTime.
Который, вместо того, чтобы создавать дополнительные структуры данных, и ссылки на них, разместит эти данные вместо самого указателя, в ситуации, когда эти данные туда поместятся.
Ну люди добрые, Вы же программисты. Если у Вас ссылка на структуру представляется 32 битами, при этом эта структура должна описать число 1, которое легко помещается в те самые 32 бита, зачем создавать структуру?
В современном V8 эта оптимизация называется Pointer Compression. Вот ссылка на статью, в официальном блоге инженеров V8, где подробно описывается это поведение.
Все последующие рассуждения автора про SMI в V8, касаются частного случая применения алгоритма оптимизации Pointer Compression. Который не обязательно будет включен для любой HOST среды. Например в Node, где используется ровно тот-же самый RunTime V8, оптимизация Pointer Compression отключена.
Как следствие, поведение в Node, связанное с обработкой численных литералов, отличается от того же поведения в браузере. Например Node может работать с 64 целыми числами если того позволяет архитектура. Чего не может делать Google Chrome. При этом Google Chrome, благодаря тому самому Pointer Compression становится в полтора раза эффективнее Node в случае обработки массивов данных, где каждый индекс укладывается в 31бит со знаком.
В чем легко убедиться используя тот же самый DebugPrint в Node и в браузере для одного и того же числа в пределах 31 бита.
Вместо ИГОГО:
Автору, как мне кажется, нужно переосмыслить весь написанный им материал и исправить допущенные им неточности. Иначе этот материал представляет из себя больше дезинформацию, нежели попытку просветить необразованное JS комьюнити.
если вы о Яндекс, то он перестал быть сколько-нибудь значимым конкурентом гугл где-то в 13-14 году, когда уже окончательно из Я были изгнаны все кто его создавал.
Задачи семантики в рамках html5 - єто формирование верстки, анализируя которую, любое сторонее программное обеспечение, которое следует тому же стандарту, может используя алгоритмы машинного анализа, зафиксировать однозначным образом, ровно тот же смысл, который был заложен автором оригинальной верстки.
В прямом смысле слова - смысл.
В случае Вашего примера с версткой, которая направлена на оптимизацию формирования отображения никакого "смысла" кроме оптимизации формы отображения - не передается.
Если Вам кажется, что я ошибаюсь, то будте так добры привести пример такого "смысла"
Я еще раз подчеркну, под термином семантика, подразумевается, в прямом смысле єто слова, формирование смысла - такого, как видит его человек.
Пример: Есть секция - черешня. Вложенные секции к ней - єто секция белая и секция красная. Как следствие формируется связь между термином Черешня и двумя связанными с ним качествами равноправными между собой: красная и белая. То есть черешня может быть белой, а может быть красной.
Пример выше, в очень упрощенном виде, иллюстрирует то, что называется семантикой стандарта html5, который разрешает задачи формирования смысла представляемого ей (версткой) контента.
Язык html, в его редакции html5, в первую очередь, направлен на представление семантики (смысла) документа (контента), посредством формирования связей между его секциями. Подавлшющее большинство тегов решают задачи определения тонкостей єтих связей.
То что нарисовали Вы в примере, не может быть принципиально реализовано на языке html, потому как Вы дали пример формирования отображения, а не описания семантики (смысла контента)
єто не знак равенства. Єто знак связывания.
Никак. И єто то самое место, где дружит императивная парадигма с функциональной.
Єтим свистоперделкам сто лет в обед.
Все отключается через chrome://flags поиск по слову omnibox
Может быть образования?
К примеру, солид дяди боба, єто попытка адаптировать естественные для функционального программирования обстоятельсва, к реалиям императивного программирования.
Стоит ли сообщить дяде Бобу, о его манипуляции с акронимами?
Еще чаще єтот код выполняется. Так может код нужно писать так, чтобы он єффективно выполнялся, а не читался?
Может в прокладке между стулом и клавиатурой? (;
Представленный материал не имеет ничего общего с официальной спецификацией языка ECMAScript. И представляет из себя как пересказ современных мифов о языке, так и, ничем не подтверждаемые, персональные представления автора.
То есть представления, которые прямо противоречат официальной спецификации.
Судите сами:
JavaScript не имел и не имеет такого механизма как EventLoop. EventLoop это специфическая для HOST среды особенность, которая, в том числе, может выполнять JavaScript код.
Например поведение EventLoop в HOST среде реализующей стандарт HTML5 описано именно в стандарте HTML5. Одновременно с этим, поведение схожего механизма в Node - описано в документации для libuv
При этом поведение в первой и второй HOST среде обладает достаточными различиями, чтобы утверждать - не может быть единого описания работы EventLoop даже в случае, если мы упрощаем задачу вычеркивая несущественные особенности реализации.
Всем свидетелям секты однопоточного JavaScript, крайне рекомендую к прочтению современную спецификацию. Например вот с этой главы официальной спецификации.
Если заявлений официальной спецификации недостаточно, то можно почитать, что об этом думают авторы спецификации HTML5
После чего, либо изменить свою точку зрения, либо оставаться адептами одно-поточного JavaScript-а.
Для тех, кто обескуражен дам краткое ИГОГО:
Спецификация языка JavaScript уже больше 8 лет, содержит в себе необходимые нормы для организации выполнения кода в более чем один поток.
Под термином поток, следует понимать не thread в его академическом смысле, но возможность организации выполнения более одной единицы кода в одно и тоже время.
Для реализации заявленного, в том числе, в официальной спецификации реализован Atomics Object регламентирующий все типичные проблемы возникающие при доступе к одному и тому же сегменту памяти разными потоками. Вплоть до создания отдельной очереди обрабатывающей таймауты для операций, которые пытаются прочитать, заблокированную другим потоком, область памяти.
В современной спецификации не существует реализации возможности самостоятельного запуска параллельного выполнения JS кода. Однако существует все необходимое, чтобы эту возможность через свое API предоставила HOST среда. Что и сделало возможным в свое время появление таких вещей как Worker-ы.
Заявленное не имеет ничего общего с тем как современная спецификация регламентирует работу JS кода.
console.log, setTimeout - это API предоставляемые HOST средой. Никакого отношения к тому, как выполняется JS код они не имеют. Ровно как не имеют отношения к тому, как выполняется асинхронный код в языке JavaScript.
Регламентируют работу этих API сама HOST среда. И только она решает как и когда будет что-то выполнено. В рамках HOST среды типичного браузера, то есть среды реализующей стандарт HMTL5 - регламентом работы для этого API служит спецификация HTML5. Где и раскрыты мистические шаги описывающие поведение setTimeout.
setTimeout это внешнее API. ВСЕ что с ним связано регламентируется HOST средой которая это API реализует. Никакого отношения к этому JS не имеет. Операция никуда не пропадает даже под соусом как бы.
Это полнейшая чушь не только с точки зрения спецификации JavaScript, но и с точки зрения стандарта HTML5 - появление в любой из очередей ссылки на задачу для выполнения какого-либо кода, происходит только тогда, когда этот код УЖЕ нужно выполнять. Иными словами, таймер или коллбэк не существует в EventLoop до тех пор пока тот самый таймер не истечет.
Где происходит истечение этого таймера? В недрах HOST среды которая обслуживает это API.
Это полнейшая чушь. Event Loop стандарта HTML5 оперирует термином Task. Task внутри себя может содержать что угодно - от одной команды до громадного блока команд. Например весь код callback функции - это один task.
Это фантазии автора, которые если и отвечают реальности - то только в одном частном случае.
В рамках стандарта HTML5, EventLoop содержит в себе две основные дефиниции: это task queue и micro task queue. Никаких макротасков и прочих тасков НЕТ.
В языке JavaScript НЕТ EventLoop. Решать задачи выполнения асинхронного кода может ТОЛЬКО HOST среда. Потому, что язык JavaScript это скриптовый язык - у которого НЕ МОЖЕТ БЫТЬ своего ввода вывода. Как следствие, язык JavaScript НЕ МОЖЕТ иметь своего API для обслуживания событий или создания тредов. Это задача HOST среды.
Нет никакого синхронного потока выполнения.
Microtask queue это калька с механизма ECMAScript спецификации HostEnqueuePromiseJob. Который создан таковым потому, что авторы спецификации Promise настаивали на строгом соблюдении порядка выполнения задач связанных с разрешением промисов.
Intersection Observer - это API стандарта HTML5 которое попало в microtask queue стандарта HTML5 по тем же причинам - авторам API было чрезвычайно важно чтобы порядок выполнения задач связанных с API был строго детерминирован. И чтобы не городить лишних огородов его просто добавили туда же.
Согласно стандарту HTML5, один EventLoop может выполнять задачи от нескольких разных Агентов. Например - браузер имеет три вкладки. Код этих трех вкладок - может выполняться одним агентом ( что было стандартом до 2015 года) и как следствие в одном EventLoop могли присутствовать задачи запускающие код, который совершенно был не связан с любым другим кодом.
В рамках этой истории, крайне важно иметь гарантии, что те задачи для которых порядок выполнения операций КРИТИЧЕСКИ важен - получат этот порядок.
Современное поведение браузера как HOST среды, по умолчанию создает отдельный Агент для каждой вкладки и как следствие отдельный Event Loop. Что продиктовано было причинами безопасности связанными с появившимся уязвимостями типа Spectre и Meltdown и схожие с ними, которых сейчас насчитывается уже с десяток.
Важно отметить, что подобное поведение негативно сказывается не только на производительности JS кода, но и на потребляемых ресурсах при дополнительных гарантиях позволяющих избегать проблем обозначенных выше.
Эта реализация не имеет ничего общего со стандартом. Например:
код пытается показать, что первым шагом выполняются все задачи из очереди microtask. Что противоречит даже логике, потому, что в заявленной очереди ничего появиться не может до выполнения хотя бы одной задачи из Task Queue.
Начало выполнения очереди microtask queue происходит ТОЛЬКО после выполнения Task из Task queue. Шаг 2.7.
В этом коде нет ничего интересного потому, что он показывает что угодно, но только не то, как работает Event Loop стандарта HTML5. И при этом не имеет вообще ничего общего с Event Loop из LibUv.
Все дальнейшее комментировать нет уже никаких сил.
Вместо ИГОГО
Использовать этот материал в образовательных целях крайне не рекомендуется, поскольку он отражает исключительно представление автора о том как это работает, одновременно вступая в прямое противоречие с официальной спецификацией регламентирующей как функционирование языка ECMAScript так и описывающей поведение EventLoop как часть стандарта HTML5.
Все пояснения материала, относительно того, как "что-то работает" не имеют ничего общего с реальностью и представляют из себя винегрет из существующих мифов и фантазии автора. (комментарием ниже я разбираю все детали єтого)
Касательно же вопроса о том откуда взялись макро и микротаски нужно сказать слюдующее:
Термин Task queue и microtask queue принадлежат спецификации html5 и не имеют никакого отношения к javascript. Однако Вы правы в том, что заподозрили связь между термином и существующей тому причиной.
Официальная спецификация языка JS седержала раньше две очереди: generic queue и promise queue которые никакого отношения к евент луп не имеют, но при єтом накладывают некоторые огранечения на то, как хост среда может выполнять тот или оной код. Авторы стандарта html5 просто зеркально отобразили єти очереди в свой стандарт, дополнив их необходимым им функционалом.
Важно понимать то, что в js нет и не может быть ничего подобного евент луп. То есть оригинальные очереди решают вовсем иные задачи нежели те, которые приписываются event loop
Автор материала совершенно запутался в том, где JavaScript (функция обрабатывающая событие), где внешнее API ( генерация events и подписка на них - то есть связывание binding функции с событием) и что именно является узким горлышком.
На фоне чего, декларация на тему "синтетической обработке событий" в "современных" js фреймворках, вызывает неподдельный скепсис относительно того, что автор понимает о чем говорит.
Любопытно еще и то, что, все тоже самое, умеет делать Google Developer Tools вызываемый из Google Chrome и подобных браузеров.
И делать все єто, он умеет уже не менее 5 лет. Кроме, разве что, создания каталогов в один клик.
Кто вдруг не в курсе - вкладка source => создать сниппет. Или комманда => открыть текущий код в source tab.
Ну и конечно все те-же самые ctrl - p, ctrl - shift - p...
Без которых работа в современном dev tools мало продуктивна.
А еще есть люди, которые сталкивались с разного рода статиской в ввиде лайков, дизлайков и т.д. И вот среди них бытует мнение, что всегда есть около 10% проголосовавших, которые пенепутали лайк с дизлайком, зеленое с красным, палец вверх с пальцем вниз, или вообще кот лег на клавиатуру.
Так что Вы меня простите, но я все же надавлю на синюю.
в каких условиях? на каком устройстве? в каком окружении?
практика - подобная озвученной, когда якобы производительность устраивает - порочна. правильным следовало бы считать практику - получения максимальной производительности в рамках доступных ресурсов как на разработку, так и на обеспечение функционирования программы.
єто фраза сказанная Дональдом Кнуттом не о том, что ненужно оптимизировать. Она о том, что нужно писать код так, чтобы компилятор мог єто сделать за человека.
В рамках архитектуры языка JavaScript, иммутабельность, а главное процесс модификации данных, делается не копированием, но путем создания цепочки прототипов.
Например у нас есть Exotic Object Array -
[1,2,3]
и мы хотим получить еще один подобный обьект с измененным элементом с индексом1
на `Primitive Value`7
.Для этого ненужно копировать обьект, а нужно сделать следующее:
То есть Вы получаете цепочку всех вычислений вышего Array, где каждый шаг изменения - это отдельный прототип.
Как следствие, никакой необходимости в копировании обьектов нет. А есть необходимость в правильной структуре данных. Что является фундаментом оптимизации любого прикладного кода.
Есть такое неписанное правило - если Вам понадобилась копия данных, то Вам нужно думать не о том, как данные копировать, но о том, что в архитектуре Вашего приложения есть ошибка.
Естественно это не касается системного программирования.
Поехали по спецификации:
delete это унарный оператор, который может удалять идентификаторы только не в строгом режиме.
Под словом удалять, подразумевается не факт того, что из Enviroment Record текущего окружения удаляется запись о идентификаторе, но подразумевается удаление ссылки (unbinding) на данные в записи идентификатора.
Как следствие этого процесса, любой код, в котором использовался этот идентификатор и который был оптимизирован будет подовергнут деоптимизации при первом же случае его выполнения.
Далее. Поскольку наш код, как мы установили, работает не в строгом режиме, это означает в том числе, возможность связывания Object Enviroment Record с текущей Enviroment Record. Как следствие, использование delete на идентификатор автоматически будет приводит и к удалению property из обьекта который связан с Object Enviroment Record.
Так же не забываем, что когда мы работаем с идентификаторами заявленными при помощи variable statement в Global Enviroment Record, это процесс будет приводить к автоматическому созданию property в global object. Как следствие применение delete к любому подобному идентификатору из Global Enviroment будет приводить к удалению property из global object
Как видим: даже если мы предположим, что delete вызывалось к идентификатору, который заявлен не в Global Enviroment и не использовался with statement (то есть мы отсекаем случай с Obejct Enviroment), даже в этом случае unbinding идентификатора с данными приведет к деоптимизации того кода, который был оптимизирован с использованием этого идентификатора.