Comments 473
Только польза от учитывания ошибок, ИМХО, сомнительная:
1. Стимулирует писать некрасиво: и так сойдёт;
2. Заставляет тратить время на поддержку возможности писать некрасиво, потенциально порождая баги;
3. Этакая криво написанная страница, простимулированная таким парсером, ещё и сломает кучу других парсеров, написанных строже;
Яндекс, Гугл даже в простом html стараются придерживаться XML, видимо, именно по причине 3.
Но если вам понадобится сверстать форматированную html-страницу с двумя картинками и парой абзацев текста — вам зачем это всё?
Насколько это типичный кейс?
Да, раньше подругому не было.
Но сейчас страницы так никто не делает и сделать так ничего толкового нельзя.
Дольше всех продержался IoT, но даже там уже не актуально и практически никто уже не верстает странички в блокноте.
Если хочется строгого четкого стандарта — всегда можно использовать XML.
И самый важный момент, если парсер браузера не будет поддерживать не строгий стандарт, на котором написаны уже миллионы сайтов, причем еще с 90-х, то зачем такой браузер, который не покажет большую часть веба?
Мне казалось, что посыл статьи как раз и состоит в указании на то, что вся эта совместимость добавила значительный багаж, который тащится и порождает проблемы, усложняющие разработки и поддержку веб-движков, а хочется сделать "правильно с нуля" (по текущим стандартам, но без багажа).
Существует стандарт по парсингу и исправлению ХТМЛа с ошибками?
Лет 10 назад я написал свой парсер хтмл и рендер машину, и тогда с обработкой ошибками был полный аут, все пытались делать как у микрософта, но он никому ничего не рассказывал и поэтому у всех был свой велосипед.
С тех пор что-то изменилось?
Всё описано в спецификации. Там есть чудный алгоритм adoption agency algorithm, а так же reconstruct the active formatting elements.
Смотрим как оно работает в описании.
Следует помнить, что сайт заблокирован, под руку попали когда телеграмм блокировали.
Есть ли например принцип, по которому «живые» тэги, попавшие например в незакрытый !--, «вытаскиваются» и обрабатываются.
Или ХТМЛ в котором 2+ BODY каждый со своими парметрами; style где то по середине и тому подобная хрень.
IE это все обрабатывает, но как именно я так и не понял.
который тащится и порождает проблемы, усложняющие разработки и поддержку веб-движков
Есть бенчмарки которые говорят, что парсинг HTML это самое тяжелое место?
Хотите изменить — изменяйте. Есть же комитет по стандартизации. А делать движок не по стандарту — это плохо. С ИЕ уже проходили.
<img></img>
, так и, чтобы было короче и красивее, <img />
.Жаль, что этот стандарт не получил развития.
Это не ошибка:
Then, if the element is one of the void elements, or if the element is a foreign element, then there may be a single U+002F SOLIDUS character (/). This character has no effect on void elements, but on foreign elements it marks the start tag as self-closing.
Движок, только выходящий на рынок, не может быть строже, чем существующие. Если хром поддерживает незакрытые теги (а он поддерживает), но и новый движок должен. Иначе сайты, "простимулированные" хромом, не будут открываться.
Яндекс — Гугл построены на одном движке — Хромиум, который выведет даже содержимое текстового файла с расширением html без доктайпа и тегов.
Если он стал лучше — то супер, но я почему-то не уверен :)
Могу я попросить Вас привести более страшный пример кода с умными указателями? Моя проблема заключается в том, что я не увидел страшного кода по приведённой Вами ссылке.
Поддерживаю. Что страшного? Разве что много вложенных шаблонов, но это в принципе на С++ зачастую так, даже без умных указателей.
RefPtr<HTMLCollection> { downcast<Document>(ownerNode()).allFilteredByName(name) }
Это какой-то свой умный указатель вебкита?
Вообще, идея отказа от умных указателей выглядит очень сомнительной. Не думаю, что именно из-за них браузеры такие тяжелые, зато они помогут не так часто выстреливать себе в ногу утечками памяти. Я немного поискал: 1, 2
- unique_ptr не имеет оверхеда по памяти и имеет оверхед по производительности в конструкторе.
- shared_ptr имеет оверхед по памяти на счетчик, оверхед по производительности в конструкторе, деструкторе, операторе присваивания. Зато разименование без оверхеда.
- По результатам у обоих в конструкторе с включенной оптимизацией небольшой оверхед.
UPD: Читаю ваш комментарий еще раз и снова смеюсь со свои «ошибочек»
Самый главный вопрос. Нафига нужен этот очень тонкий враппер над std::string?
Главный вопрос C++ программирования и всего такого: а писал ли ты свою реализацию строк/враппер над ними? Вот мужики теперь похвастаться могут.
Мне хватило ужаса от приведённых ранее ссылок, а Вы ещё больше пугаете.
Мои варианты ответа на вопросы:
2. Я бы постарался уменьшить количество таких inline методов в определении класса в принципе. Во-первых, это значительно усложняет понимание интерфейса класса, т.к. необходимо в куче кода выловить прототипы функций-членов. Во-вторых, если код не идеален и приводит к генерации предупреждений компилятора, то для каждого файла, в который включен заголовочный файл с определением класса, эти предупреждения будут генерироваться, что сделает сами предупреждения полностью бесполезными. Я с такой проблемой сталкивался, когда работал с H3D: включение заголовочных файлов H3D приводило к генерации 1500-2000 предупреждений.
6. std::find?
7. Можно поиграться со SFINAE, но в простейшем варианте я бы сделал так:
template<class ValueType>
void fromValue (ValueType i_value) {
data_ = std::to_string (i_value);
}
А есть ли у вас режим редактирования?
Почему спрашиваю: есть всем известные движки html, со всеми наворотами, но совсем нет удобных WYSISYG редакторов более легких форматов — таких как Markdown, FB2/FB3 и т.д. Или их делают на основе движков html типа Webkit и тащат вместе с движками кучу лишнего, т.е. написание такого редактора сводится к затыканию дыр и возможностей вставить в редактор то что там не должно быть. А чего-то простого и минималистичного, не завязанного на браузерных монстров — нет.
не путать с QWebEngine* компонентами.
На данный момент ваш движок поддерживает парсинг HTML и кое-как парсинг CSS? Т.е. по сути он не умеет вообще ничего и на данном этапе совершенно бесполезен как таковой?
Я посмотрел ваши исходные коды на гитхабе и, честно говоря, ННП. Если вы этой статьей планировали привлечь людей к разработке, то крайне советую хоть какое-то структурное описание проекту сделать, и желательно всё-таки оформить файлы исходных кодов, а то те редкие комментарии (причём на русском) не помогают от слова совсем.
В целом, желаю удачи в этом нелёгком начинании. Был бы заинтересован помочь, если дело сдвинется хотя бы до рендера страничек :)
В данном случае инвесторов можно свободно заменить на читателей. Почитать это хорошо, но хотелось бы чего-нибудь наглядного — какие-нибудь тесты, пусть даже глуповатые типа «парсим миллион тегов в секунду». Это было бы куда более привлекательно, как мне кажется.
Зависит от ировня интерактивности, для начала можно отображать статичную страницу с применеными стилями и, опционально, возможностью перехода по гиперссылке. Как мне кажется, этого уже достаточно, чтобы его можно было начать использовать где-нибудь еще и привлечь внимание разработчиков.
К общим замечаниям, если планируете привлечь других разработчиков, то выложите в репозиторий правила форматироавния для какого-нибудь распространенного автоформатера кода. Судя по всему вы форматируете код в ручную, что не очень хорошо для привлечения других разрабоотчиков — не все форматируют как так же. Так же попробуйте начать использовать тесты, проект новый, принимаемые решения могут оказаться не удачными спустя какое-то время, а с тестами и рефакторинг проще, и частично они помогу прояснить, какое поведение ожидалось.
Движков не 4, а куда больше, десятки если не сотни.
Парсинг HTML/CSS это меньше 5% от задачи даже с учетом расчета параметров. Хотя все параметры все равно не посчитать — многие от редеринга зависят.
5% расчет реальных параметров тегов (зависящих от дисплей и их наследование)
5% рендер имиджей (включая динамические и background всех мастей)
5% разбивка и рендер текста
5% рендер с учетом параметра flow
15% рендер таблиц
10% веселуха с импут котролами
5% форматирование после ресайза
5% движение по документу (скрол линки и т.п.)
10% борьба с чарсетами, иероглифами и поломанным блин UTF
5% динамическая загрузка мегабайтных документов и как следствие перефарматирование всего предыдущего
10% печать документа и особенно инпут контролов :)
3% доводка для тестовых ХТМЛ (есть где то для проверки стандарта)
6% обработка багованных ХТМЛ
и уже не помню, что там еще из время затратного
- API для DOM (выполнено)
- Основное API для CSS OM (выполнено)
- Парсеры и сериализаторы всякие (выполнено)
- Взвешивание селекторов и проверка элементов на соответствие селекторам (выполнено)
- Каскадирование стилей (выполнено)
- Генерация контента с помощью псевдо элементов css (выполнено)
- Метрика стилей и компоновка
- CSS OM API для элементов DOM (ну там, страницу прокрутить)
- Рисование всего этого на экран с учетом прокрутки
- Возможность выделять страницу
- Нативные контролы
- Ивенты для псевдо классов CSS
- Виртуальная машина JavaScript и события
- SVG 2.0
- Скачивание самой страницы по HTTPS
- А там дальше ваши Canvas, WebGL, Video, XHR, Fullscreen requrest-ы, ...
- А, про DevTools забыл, но инспектор dom со стилями думаю будет несложно сделать
И все равно это даже не 20% браузера. Надо будет вечность дописывать например, систему загрузки файлов, систему post/get, различные шифрования, поддержку сотен других инструментов.
ИМХО, нафиг — это все дорого и бесперспективно.
Глядишь, и не нужно будет трать столько усилий на написание и поддержку браузерного движка.
Компиллятор — он используется локально и генерирует совместимый с существующими ОС и процессорами код.
Т.е. остальным участникам не нужно ничего менять.
phantom-code предлагает заменить весь существующий веб на какую-то новую технологию.
Резюме: временами полезно переписывать с нуля оси, компилеры, браузеры и иные базовые вещи нашего мира. Но бросая всем вызов, лучше быть всё же аспирантом американского универа! ;-)
остальным участникам не нужно ничего менять.Хе, ну скомпилируйте Linux kernel чем-либо кроме gcc! Apple лишь за пару лет перевёл свою инфраструктуру на LLVM! Аналогичные принципы, компилер — браузер, а веб-ресурсы — программы.
Так ваш пример про аспиранта, а не про корпорации. Корпорации намного инертнее одного человека. Может за 20 лет и поменяют, почему нет?
все так и происходит. Вышеозначенные компании находятся во всех инициативных и исполнительных группах, перепиливают старые стандарты, пишут новые, форсируют переходы на новые технологии.
у них мировая аудитория. Они допиливают до удобоваримого состояния внедренное, параллельно разрабатывая новое на будущее.
Три года могут показаться «не такими большими», но за 3 года Angular потихоньку поменялся на Electron, а C++14 на C++17. В мире ПО 3 года достаточно, чтобы возникла новая технология и тихо умерла. Так что жить нам с HTTP/1.1 еще очень и очень долго :) И поддерживать его.
P.S. Кстати Xorg пытались выпилить Вэйлендом, но не взлетело, впрочем примерно понятно, почему. Да и сам Вэйланд почти целиком эмулирует Xorg.
Не стоит путать легаси с надежным, проверенным временем решением. Должна происходить постепенная эволюция, а не революции с майданами. Когда горячие головы, терзаемые NIH-синдромом без десятков лет опыта за плечами, приходят с лозунгами: «а давайте всё перепишем!» — ничего хорошего на выходе не получается.
Достаточно коротко и ясно происходящее описал легендарный Poul-Henning Kamp в своей заметке: queue.acm.org/detail.cfm?id=2716278
Но это всё мелочи, мы сходимся в базовом аргументе — нельзя просто взять и сделать новый Интернет, уже слишком поздно для этого. А всё остальное — холивары :)
HTTP до сих пор использует отдельное TCP соединение для каждого нового запросаИ это правильно, так и должно быть. А от того ужаса, который вышел в виде SPDY и HTTP/2 ещё долго придется плеваться. И да, в результате в SPDY и HTTP/2 гораздо больше накладных расходов.
Однако, одно соединение на один запрос довольно избыточно.В чем заключается избыточность?
В чем, по вашему, правильность данного метода?В том, что TCP это протокол транспортного уровня и проблемы транспортного уровня должны решаться на транспортном уровне. Один запрос — это один поток данных. Один поток данных — одно независимое TCP соединение. Это правильно, это позволяет применять flow control на уровне каждого потока, а также роутить эти запросы независимо друг от друга. Они могут обрабатываться разными серверами, они могут идти разными маршрутами. Всё это позволяет лучше масштабировать нагрузку и лучше справляться с ошибками.
Даже для реализации «сессии» пришлось придумывать костыли.В чем заключаются костыли? HTTP — это stateless протокол, благодаря этому он очень хорошо масштабируется, с помощью него можно реализовать удобный и красивые RESTfull интерфейсы. Не будь он stateless, костыли бы пришлость расставлять повсюду.
Теперь каждый второй сайт уведомляет о том, что он использует cookie и просит понять и простить. А все из-за того, что «это правильно, так и должно быть».Смешались в кучу кони, люди, мухи, котлеты… Каждый второй сайт уведомляет об использовании cookies согласно новому закону евросоюза. Это не имеет никакого отношения к протоколам, а является законодательным актом.
Более того, работа с cookies и сессиями, как и вся остальная семантика HTTP — совершенно одинаковая, что в HTTP/1.1, что в HTTP/2 и SPDY.
Работу с сессиями вероятно можно было бы улучшить, но это никак не связано с количеством TCP соединений, и ни HTTP/2, ни SPDY — вообще ничего в этом отношении не улучшают.
В чем заключается избыточность?Установка соединения (SYN->ACK->ACK) с передачей cookies для каждого запроса дает лишнюю нагрузку на сервер и на канал. Для одного клиента она не существенна, но когда клиентов тысячи, она внезапно начинает играть свою роль. А если мы вспомним, что внутри у нас plain text, то становится еще грустнее.
Смешались в кучу кони, люди, мухи, котлеты… Каждый второй сайт уведомляет об использовании cookies согласно новому закону евросоюза.Безусловно. Только сами cookies появилсь, чтобы сервер мог хоть как-то хранить на клиенской машине информацию и различать сессии между собой. Исторически, это был именно костыль.
HTTP — это stateless протоколМое исходное сообщение было не про «улучшение» HTTP или HTML, а о полном переосмыслении всего веба. В текущем состоянии эти технологии обладают большой гибкостью, но нещадно жрут ресурсы.
Возьмем к примеру QML. По сути QML реализует связку HTML+CSS+JavaScript (безусловно после определенной доработки), но при этом быстрее и выглядит на всех устройствах одинаково. Не требуется для каждой страницы подтягивать портянки bootsrap/jquery/etc (я понимаю, что браузеры кешируют данные, это всего лишь пример).
Более того, работа с cookies и сессиями, как и вся остальная семантика HTTP — совершенно одинаковая, что в HTTP/1.1, что в HTTP/2 и SPDY.Доработки и улучшения — это хорошо. Но я говорю о «попробовать спроектировать с нуля исходя из текущего опыта». Я понимаю, что это не быстрый процесс и его внедрение может занять многие годы. Но иногда требуется отбросить обратную совместимость и дать дорогу чему-то принципиально новому.
С сжатием уже не plain text. Да, остаются еще заголовки, но есть WebSocket.
но при этом быстрее и выглядит на всех устройствах одинаково.
Он быстрее ровно настолько, насколько оптимизирован Qt. При этом там так же есть свои нюансы. Например под iOS нет JIT компилятора для QML.
С сжатием уже не plain text. Да, остаются еще заголовки, но есть WebSocket.На сжатие/распаковку требуются ресурсы процессора (как сервера, так и клиента).
Он быстрее ровно настолько, насколько оптимизирован Qt. При этом там так же есть свои нюансы. Например под iOS нет JIT компилятора для QML.Конкретно QML был всего-лишь примером.
Установка соединения (SYN->ACK->ACK) с передачей cookies для каждого запроса дает лишнюю нагрузку на сервер и на канал. Для одного клиента она не существенна, но когда клиентов тысячи, она внезапно начинает играть свою роль. А если мы вспомним, что внутри у нас plain text, то становится еще грустнее.Нагрузка от TCP хэндшейка просто смешная по сравнению с дополнительной нагрузкой, которую дает реализация ещё одного пакетного слоя для мультиплексирования и ещё одного flow control внутри соединения. Для работы HTTP/2 требуется больше накладных расходов и больше пересылать TCP-пакетов, а также расходуется больше памяти и больше процессорных ресурсов. А внутри по сути такой же plain text, который также нужно парсить.
Безусловно. Только сами cookies появилсь, чтобы сервер мог хоть как-то хранить на клиенской машине информацию и различать сессии между собой. Исторически, это был именно костыль.А как нужно их хранить и где по вашему? В чём же заключается «костыль» и кто мешает хранить простой ключ сессии, как в общем-то многие и делают?
Но иногда требуется отбросить обратную совместимость и дать дорогу чему-то принципиально новому.Наверное такие решения должны прорабатываться, обсуждаться и приниматься с особой осторожностью, чтобы не сломать то, что работает годами, не сделать хуже. А сейчас мы видим то, что большие корпорации проталкивают свои протоколы в своих корыстных целях, при этом заставляя всех остальных страдать. Как в своё время было с Microsoft и IE, сейчас то же самое происходит, только в руках одной мегакорпорации оказались, как самые популярные браузеры так и самые посещаемые веб-ресурсы, а потому они в результате затачивают веб под себя, наплевав на остальных. Имея при этом большие маркетинговые ресурсы, они всё это подают под соусом улучшений и инноваций, легко одурачивая основную массу, которая плохо себе представляет работу сетевых протоколов и повторяет из статьи в статью одни и те же заблуждения касательно HTTP/1 vs 2.
А как нужно их хранить и где по вашему? В чём же заключается «костыль» и кто мешает хранить простой ключ сессии, как в общем-то многие и делают?Я бы хранил все данные на сервере и отдавал клиенту только его ID или ID сессии. Костыль заключается в том, что сначала был разработан stateless HTTP, а уже потом появилась необходимость различать сессии/клиентов, в результате чего появились cookies. Конечно, если рассматривать stateless как преимущество, то это уже не костыль. Лично я не вижу особой необходимости в stateless протоколе, но готов поверить вам, т.к. в данном вопросе не имею достаточно опыта.
Наверное такие решения должны прорабатываться, обсуждаться и приниматься с особой осторожностью, чтобы не сломать то, что работает годами, не сделать хуже.Да, именно взвешенное решение, выработанное в ходе обсуждений я и имею в виду.
Так собственно, в большинстве случаев все так и работает — сервер хранит все у себя, а клиенту отдает ID в виде одной куки.
Вообще, кука в любом случае нужна, ибо мир не идеален, и сессии могут рваться. В вашем случае — клиент переподключается и получает новую сессию. А если он хочет восстановить старую — ему опять же нужна кука в каком-то виде.
И опять же, тут возникают вопросы — если этот ID придумывает сервер — то это совершенно ничем не отличается от куки.
Если ID выбирает клиент — то как гарантировать уникальность? Как защититься от перебора? Надо что-то типа GUID, и то GUID не гарантирует защиту от перебора. Нужен более длинный идентификатор. Дальше — один GUID для всех серверов? Так нельзя, потому что тогда юзера можно трекать по всему Интернету без особых проблем. Значит нужно генерить GUID для каждого сайта.
Тут возникает вопрос с поддоменами. a.example.com и b.example.com — это разные сайты или один? На самом деле может быть и так и так.
В общем случае — разные, значит будут свои GUID. Значит, нельзя трекать авторизацию между подсайтами. Например, если я хочу оставить комментарий на user1.livejoural.com — мне надо логинится. Если потом хочу оставить комментарий на user2.livejournal.com — надо логиниться снова, потому что GUIDы будут разные и сайт не узнает что я — это я. С куками проще. Сайт выдает куку для *.livejournal.com и все.
Ну и самое страшное — уже писали сверху. Веб становится строго stateful и значит резко усложняется горизонтальное масштабирование. Грубо говоря, в куку можно запихнуть id пользователя, подписать ее и тогда любой сервер кластера будет знать что вы — это вы, даже без синхронизацию через общую базу.
Нагрузка от TCP хэндшейка просто смешная по сравнению с дополнительной нагрузкой, которую дает реализация ещё одного пакетного слоя для мультиплексирования и ещё одного flow control внутри соединения.Она по нагрузке на ЦП, может, и смешная, а вот по времени и оверхеду данных, особенно для маленьких файлов — настолько несмешная, что бандлинг JS и CSS сейчас почти везде используется по умолчанию. И это я ещё молчу про тайлинг картинок.
В том, что TCP это протокол транспортного уровня и проблемы транспортного уровня должны решаться на транспортном уровне. Один запрос — это один поток данных. Один поток данных — одно независимое TCP соединение.
Звучит правильно, но… но… ведь так можно оправдать дизайн протокола FTP :-)
А что с ним? Если не учитывать неактуальные уже фичи типа перекодирования байтов, и неактуальные на момент создания протокола вопросы безопасности, он прекрасен своей простотой и тем, что работает. Просто работает. И понятно куда смотреть, если не работает как ожидалось.
Наоборот :) команды передаются по tcp в похожем на http текстовом виде, а данные — в отдельном tcp соединении, просто байты без мультиплексирования, оверхеда на какие-нибудь заголовки и переконвертирование. То есть передача файла работает всегда с максимальной скоростью, сколько можно выжать из tcp в данном канале. Но многие реализации серверов имеют упоротые лимиты и дефолтные настройки, например размеры буферов, поэтому можно наблюдать тормоза на ровном месте.
информация передается в текстовом видеИнформация давно уже передаётся в сжатом виде, а текстовый оставлен только для совместимости.
1) Производителям браузеров все равно прийдется поддерживать старые стандарты, так как на них написано уйма сайтов, которые обновляться не будут, но которые могут быть важны отдельным пользователям.
2) Надо переучиваться всему сообществу веб разработчиков, выпускать новые книги, новые учебные курсы и т.п. — это встретит большое сопротивление!
Привет!
Я уже было обрадовался, подумал вот, есть такие же психи как и я. Но, посмотрев исходники разочаровался.
1) Каким спецификациям соответствует парсинг HTML? Я так понял, что вы из головы написали парсер. Штука эта давольно сложная, тем более чтобы написать её правильно с заделом на будущее. Судя по вот этому о скоростях мечтать не приходится. Это действительно весь HTML парсер? Это тоже странно выглядит.
2) Каким спецификация соответствует парсинг CSS? Опять же, судя по коду никаким. Вы просто взяли из головы то, что знаете о CSS и сделали для этого парсинг. Вообще, CSS раздербанить ни фига не простая задача. Уж поверьте моему опыту.
3) У вас не верно сделана сериализация HTML. Точнее сказать, она сделана из каких-то ваших соображений. В спецификации чётко описано поведение сериализатора.
К сожалению, вы не сможете показать страницу быстрее других, у вас для этого ничего нет.
А теперь попугаю, немного :).
У вас исходники всего этого дела занимают 312КБ. Чтобы хоть как-то оценить насколько ничего нет: в проекте lexbor один только html парсер занимает 1.8МБ. DOM, в котором почти ничего нет, только минимум для создания и удаления нод, элементов, атрибутов 100КБ.
Чтобы понять масштаб того, что надо делать посмотрите мой roadmap, и это процентов 10 от полноценного браузерного движка.
Ваши бы силы да в нужное русло.
Поправьте меня если я где-то ошибся.
Я не понял, важнее функционал или размер исходников?
Важно, чтобы ожидания сходились с заявлениями. У вас, к сожалению, нет парсера HTML, CSS, у вас нет сериализаторов. Да и странно заявлять о сериализации даных. Куда важнее заявить о парсинге чанков, парсинге фрагментов. У вас нет работы с неймспейсами. Не знание HTML спецификации сразу кинулось в глаза после фраз о кавычках, это самое стандартное поведение, зачем это оговаривать отдельно? У вас есть что-то, что вы сами придумали и назвали это парсером HTML, CSS.
Я никак не пытаюсь «наехать». И я искренне обрадовался когда прочитал заголовок, но по факту у вас пустышка + непонимание базовых вещей. Если вы хотите, то можете написать мне, что нибудь да обсудим.
Размер тут как показатель, на глаз прикинуть.
Чанки (chunks) — фрагменты.
Браузеры процесят хтмл кусками. Прилетело по сети 4к данных, эти данные идут на парсинг и так далее. Данные могут быть прерваны в любом месте, соответственно и продолжить обработку надо уметь с того места где закончил. Но, тут магии нет, если ты посмотришь на спецификацию то поймешь, что она написана так, чтобы это работало "из коробки". Токенизатор на вход принимает codepoint (unicode) по одной штуки и решает куда дальше рулить. Это обычная стейт машина.
Фрагменты — парсинг хтмл фрагментов очень важен. Это так называемый innerHTML. Штука эта довольно тяжелая для выполнения. Как оно должно работать так же описывает спецификация. Тяжелая она потому, что для неё необходимо создавать новый парсер, новый Document объект и root element + всякая логика.
Сделать, хотя бы, парсинг хтмл быстрым задача тоже интересная.
Ты, конечно, молодой и активный. Но прежде чем делать громкие заявления изучи как устроены текущие браузеры, посмотри почему они все отрабатывают страницы одинаково (спецификации).
Конечно, фигачить из головы куда интереснее. Делать что-то по спецификациям нудное занятие.
Чтобы что-то сделать лучше необходимо понять текущие проблемы. Нужен опыт. У тебя, к сожалению, опыт отсутствует как в программировании так и в понимании браузерных движков.
Но шуму ты наделал много.
Ну, а как вы создадите ещё одно дерево? Понятно, что парсер можно создать один раз и держать его при себе. Всё остальное прийдется создавать каждый раз. Потому, что во время парсинга всё это используется/необходимо. Думаю, напишу статью о том как всё устроено в хтмл. Можете посмотреть в спецификацию: https://html.spec.whatwg.org/multipage/parsing.html#parsing-html-fragments
Собственно, по этому innerHTML крайне дорогая штука в браузерах. innerHTML — это и есть парсинг фрагмента. Всегда лучше пользоваться напрямую через интерфейсы.
Нет. Не быстрее.
Дорого звать из js функции движка. innerHTML быстрее если нафигачить туда много HTML. Если сделать чистый тест по одному тегу, к примеру
<div>Текст</div>
и покрутить в цикле с реальным добавлением в текущий документ, то innerHTML проиграет в 3-4 раза.
Более того, если в innerHTML отдать сразу 1000 тегов и тоже самое создать с помощью дом то время выполнения будет почти одинаковое.
Но если в innerHTML зафигачить сразу кучу хтмл-а то он отработает быстрее. Потому, что он сразу передаст всё в движок и не будет делать вызовы по Н раз.
Отсюда, надо понимать, что и как использовать.
Код для примера:
1-2 mc
<div id="aaa"></div>
<script>
let aaa = document.getElementById("aaa");
let t0 = performance.now();
let node;
for (let i = 0; i < 1000; i++) {
if (node) {
aaa.removeChild(node)
}
node = document.createElement("div");
let text = document.createTextNode("Text " + i);
node.appendChild(text);
aaa.appendChild(node);
}
let t1 = performance.now();
let res = document.createTextNode("Time: " + (t1 - t0) + " milliseconds.");
aaa.appendChild(res)
</script>
7-8 mc
<div id="aaa"></div>
<script>
let aaa = document.getElementById("aaa");
let t0 = performance.now();
for (let i = 0; i < 1000; i++) {
aaa.innerHTML = "<div>Text " + i + "</div>";
}
let t1 = performance.now();
let res = document.createTextNode("Time: " + (t1 - t0) + " milliseconds.");
aaa.appendChild(res)
</script>
Я ну пойму, вы что хотите доказать?
Я вам доказал, что innerHTML внутри отрабатывает дольше на простом примере. Зафигачте 1000 элементов через innerHTML:
var html = "<div>Текст 1</div>...<div>Текст 1000</div>"
aaa.innerHTML(html)
B попробуйте создать те же самые элементы в цикле через дом добавляя их по одному в aaa.appendChild(node).
Скорость будет почти одинаковая. Это как доказательство, что основное время уйдет на оверхед.
Я опроверг ваше заявление:
Но innerHTML и DOMParser.parseFromString отрабатывает быстрее, чем постройка дом-дерева через методы DOM API по отдельности.
Опять же, выше я вам объяснил где будет выигрывать innerHTML.
Что это за синтетический тест, с измерением перфоманса на создание 1-2 дом узлов, когда один из них текстовый? Зачем это нужно делать через парсер адекватному человеку?
Вполне себе хороший тест. Показывает, что innerHTML медленнее. А точнее то, что вы не правы со своим заявлением, что он быстрее.
Давайте вы добавите в свой узел пару другую вложенных элементов, а еще назначите им атрибуты. И замерите снова.
Простите, но добавляйте сами, что хотите. Простым примером вам было показано как оно отрабатывает. Я хорошо знаю как оно устроено внутри и могу создать тесты там где inner выиграет и проиграет. Но выше я создал именно голые тесты, равные условия, чтобы показать, что вы не правы.
При этом я дописал, что:
Отсюда, надо понимать, что и как использовать.
Вы специально искажаете всё? Читайте комментарий выше.
Я говорил, про 1000 элементов, а вы тут тестите 100000 тысяч.
Да, я выше написал, что innet будет выигрывать если ему много сразу зафигачить. Потому, что оферхеда не будет на вызов функций из js.
Но, даже при этом, при вашем тесте с котором я согласен был даже выше, что innet будет выигрывать если ему много дать, построение дом проигрывает всего в два раза. При вызове 100000 функции которая сходит в движок.
Извините, что не в тему.
Чувак, реально, ты тратишь силы в пустую. Это круто для опыта, но толку от этого никакого. Хотя, скорее всего, в твоём возрасте толк и не нужен, я хз.
Только не кидайте тапками, если имели ввиду другое.
Нет, не то. Твоя ссылка это не синтаксис. Я привел ссылку на граммар. То есть, то как надо парсить токены которые создает синтаксический парсер css ( drafts.csswg.org/css-syntax-3/#tokenization ). В парсере css ты получаешь токены, не байтовый поток и не юникод. Читай ссылку.
Вообще, я тут создал чат в телеграме. Присоединяйтесь, будем обмениваться идеями :-) t.me/dev_browser
Как вы поймёте, что сайт «нормально» отображается с помощью вашего движка? Что это будет за урезанная спека которая сможет предоставить весь нужный набор опций для верстки и будет лучше чем сейчас?
Чтобы вам хоть как-то попытаться пропихнуть свою спеку вам надо стать гуглом, и то не прокатит.
Есть стандарт который все знают и поддерживают, опираются на него. Идея написать свой движок, но если чего отдавать на отрисовку гуглу за гранью разумного.
Определять просто — специальным флагом в коде разработчик явно берёт на себя обязанность соблюдать более строгие требования. Подумать о том, как можно было улучшить текущий стек, я и предлагаю подумать. У меня, разумеется есть куча идей разной степени тяжести.
И давайте вы свой пессимизм оставите ведру с крабами. Возможно тот же гугл заинтересуется проектом, когда он покажет свои преимущества. Глаза боятся — руки делают. А если вам страшно так, что руки немеют — так вас никто не заставляет. Каждый сам решает чем ему интересно заниматься.
Никто не знает веб стандарты в полной мере. Это одна из бед этого переусложнённого бардака.
Судя по вот этому о скоростях мечтать не приходится. Это действительно весь HTML парсер? Это тоже странно выглядит.
Там кстати можно применить оптимизацию habr.com/post/166201
У html тегов длиннее 9 символов начальные части не пересекаются, поэтому их можно отбросить при вычислении хэша.
Хм, интересная точка зрения. И деструкторов в классах я что-то тоже не вижу, очень интересно)
Вы уверены, что GC это добро?
Без рендера неинтересно — это самое сложное. А парсеры может написать почти кто угодно, особенно если не соблюдать стандарты и не делать оптимизаций
Какие все злые. Сами бы не сделали и доли того, что сделал автор. Потому что сложно, лень, никому не нужно, всё равно будет не по спецификациям и т.д. Разве это всё важно? Задумка интересная, автор молодец.
Аффтар НИЧЕГО полезного не сделал, сколько бы строчек ненужного кода он в этот проект не накидал. Ибо, как активно делающий web scrape на java, авторитетно заявляю, даже если ему ещё 20 студентов (что маловероятно) дать в помощники, они не будут успевать. И уж точно это не будет самый быстрый и «архитектурно правильный» движок.
Самый продвинутый headless browser под java — HtmlUnit пилит команда из человек 5, причём безбожно проигрывают в гонке. Если 4 года назад можно было почти всё скрейпить, сейчас чуть ли не каждый второй сайт с авторизацией выпишет облом.
При этом безголовый браузер это далеко не полноценный браузер. Нужна лишь навигация по DOM.
В общем, через много лет это будет в самом лучшем случае что-то вроде chromium с выключенным js. Но в хроме я, когда сильно хочется, жму кнопочку «включить js», а у них такой волшебной кнопочки не будет.
P.S. Часть фич ES6 мой интерпретатор, кстати, умеет, включая стрелочные функции, block-scope variables и Promises.
У меня уже стоит Tortoise SVN, и я коммичу каждое небольшое изменение на старый вузовский сервер. Я пробовал ставить параллельно Tortoise Git, он мне мало того, что показался менее стабильным, так они вдвоём ещё и немного конфликтуют… Прямо хоть под другой ОС его ставить, я не знаю. Или использовать консольную версию Git.
Но с репозиторием SVN можно работать и через Git. Получается, в целом, не плохо. Я работал с SVN через меркуриал (hgsvn) и git-svn. В целом, git-svn поудобнее, но бывали проблемы с клонированием SVN репозитория — если он большой, то клонируется очень долго, и иногда падает — приходилось подбирать параметры. С hgsvn такого не было, но он и не клонировал репозиторий, это фактически было в одном каталоге два репозитория — SVN и меркуриал, а утилита hgsvn позволяла их синхронизировать. Это было менее удобно, но позволяло не вытягивать при помощи hgsvn всю историю, а пользоваться историем SVN.
А если резюмировать: вот у меня случай чайника (коммиты редко, больше одной ветки не нужно, это только вносит путаницу, надо просто чтобы была возможность быстро написать текстовое сообщение и вкоммитить) — какое решение сейчас для меня будет наиболее оптимальным, если от старого SVN репозитория я отказываться не хочу?
Когда ставил Git, пытался делать разные ветки на разные добавляемые фичи, потом их сливать — в итоге действий было много (а по факту ветка не жила дольше 1-2 коммитов), и не всегда делалось то, что я хочу (то есть меня даже GUI не спас).
Может, попробовать какой-то вариант примерно как у вас был, с автосинхронизацией и подтягиванием истории из SVN? Только я хотел бы синхронизировать с Git, а не с Mercurial, и чтобы оно сразу при коммите в SVN на GitLab бы отправлялось.
Работа с Git/Меркуриал подразумевает большее количество шагов — добавить в "индекс", сделать локальный коммит, отправить коммит на сервер.
Если Вы работаете с репозиторием один, то использование практики ветка-на-фичу, мне кажется излишней — потренироваться работать с ветками — да, пожалуй, но на постоянной основе — особого смысла нет. Это дает преимущества когда над проектом активно работает несколько человек. В этом случае удобно использовать ветки, чтобы не вливать сырые изменения в основную (trunk/master).
Я использовал связку, так как в процессе работы мне было удобно делать локальные коммиты и отправлять промежуточные результаты работы в отдельный hg-репозиторий (потом git-репозиторий). Срок выполнения задачи был большим, поэтому я делал коммит каждый день с тем на чем закончил, иногда делал дополнительные ветки, чтобы попробовать какой-нибудь альтернативный вариант решения. После того как задача решена, объединял все коммиты в один и отправлял в SVN.
К сожалению одной командой отправить изменения в SVN и другой git-репозиторий не получится. Не зависимо, что Вы выберете git-svn или hgsvn сценарий будет примерно такой:
- внести изменения в индекс (stage)
- сделать локальный коммита
- отправить изменения на сервер SVN
- отправить изменения на сервер Git (Меркуриал)
Кажется, что tortoise git как раз и делал отправку изменений на сервер сразу после комита, но могу ошибаться. Я не очень люблю клиенты для git, так как в них очень легко можно наворотить что-нибудь не то, а потом придется разгребать. С этим сталкивался не раз, поэтому предпочитаю работать с консолью — выше осознаность действий.
tortoise git сам ничего не пушит, но он позволяет это сделать в один клик после коммита.
Через консоль сломать git репозиторий куда легче, чем через гуй. У mecurial с этим получше.
С копированием я разберусь, а вот как через консольный Git сделать сразу коммит и пуш на гитхаб, не подскажете?
git commit -mУже почитал в статье про введение в Git (точнее, в руководстве по загрузке проекта на гитхаб). С текстовым редактором — имхо это какая-то странная механика, особенно как для Windows. Как программа поймёт, что файл готов? Мониторит файловый дескриптор, отслеживая закрытие текстового редактора?
Должен сказать, что пока ещё очень многое не реализовано: нет поддержки фреймов, таблиц, элементов форм. Даже box-sizing пока реализовать руки не дошли (по умолчанию расчёты ведутся в режиме border-box ради удобства отладки и наглядности).
Однако на днях я реализовал в JS движке методы Promise.all и Promise.race, реализовал там же корректные вычисления с бесконечностями (раньше бесконечности просто не поддерживались в принципе), сделал нумерованные списки нескольких видов в рендер-движке (включая нумерацию римскими цифрами и латинскими буквами). Также ввёл в JS-движке скрытие возвращаемых значений при установке таймеров, чтобы не засорять вывод (однако, его можно активировать с помощью статического поля класса в несколько доработанном виде).
github.com/popov654/tinybrowser
А что на счёт поведения этих функций говорит стандарт?
Надо почитать. За стандарт не скажу (не читал), но когда у нас с точки зрения математики результат вычисления — плюс или минус бесконечность, то это скорее NaN (особенно если нет специальных констант, как в Java), чем непонятная фигня с плавающей точкой, которая проверку isNaN() не проходит (возвращает false).
Кстати, оказывается, в JavaScript ещё есть функция isFinite() (стыд и позор мне, не знал про неё). Так вот, внимание —
isFinite(tan(Math.PI / 2))
возвращает false! Стандарты стандартами, но здравый смысл подсказывает, что это бред.То есть 5++?
Именно так. Не то чтобы в этом был практический смысл… Но если есть возможность отличить
-1
от --1
(по числу минусов) и ++3
от +3
(по числу плюсов) — то нет особого смысла падать с ошибкой, если можно посчитать выражение по тем же правилам, что и в случае переменной (только сайд-эффектов не будет).Если есть возможность отличить -1 от --1 (по числу минусов) и ++3 от +3 (по числу плюсов)
5++-5
— это (5++)-5
или 5+(+(-5))
? Ведь +-5
в js — валидная операция.+-5
Хм. Не знал про такой нюанс. Но писать +-5 смысла даже ещё меньше, чем 5++: поменяли два раза знак и получили то же, что было. Причём у нас заведомо integer (потому что литерал), а не, например, boolean, поэтому это даже для преобразования типа в данной ситуации бесполезно.
И вообще — писать код, не ставя пробелы — ужасно дурной тон. Напишите 5++ -5, и вопросы отпадут сами собой. Мой парсер смотрит код посимвольно, а пробел — гарантированный признак конца токена.
Текущая же реализация парсера именно при вашей форме записи воспримет это именно как (5++)-5, потому что скобок нет, а анализ идёт слева направо.
писать код, не ставя пробелы — ужасно дурной тон.
Минификация же.
но и пожмет все названия переменных и функций до 1-2ух символов
Я знаю об этом.
минификацию используют на сегодняшний день почти все (и правильно делают)
Нет, не правильно. Из-за этого код становится намного сложнее анализировать (хотя для людей, его писавших — это даже плюс, но я не про них сейчас, а про всех прочих). Ценность же анализа просто огромна для самообучения и развития.
Насчёт выгоды от уменьшения размера после минификации — она вовсе не так велика, как вы говорите. Даже вк до перехода на новый дизайн не минифицировал свои скрипты (можете даже посмотреть сами на wayback machine, если что).
Опять же, GZIP прекрасно справляется с тем же самым: заменяет наиболее часто используемые паттерны (включая длинные повторяющиеся имена переменных) на специальные байтовые последовательности, причём чем паттерн встречается чаще, тем его код короче. Это в сто раз лучше и грамотнее, чем ваша минификация.
Не говоря уже о том, что для очень маленьких сайтов, где все скрипты весят меньше 800-1000 Кб, вообще можно не использовать ни минификацию, ни сжатие: каналы сегодня быстрые, а часть данных — кэшируется браузером и не будет загружаться при каждом запросе повторно. При грамотно же настроенном кэшировании на стороне сервера можно и вовсе получить гарантию кэширования всей статики на N часов или суток.
Выгода от минификации колоссальна в масштабах всего интернета, если вы этого не понимаете, да ещё и утверждаете обратное, то и говорить не о чем.
Давайте разделим на 2 части.
1) Удаление неиспользуемого кода.
Все модные инструменты вроде вебпака НЯП это делают всегда.
2) Сжатие имен переменных, выделение общих частей строк и т.д.
Мне тоже непонятно, почему минификатор сделает это лучше чем Brotli.
Наоборот, вебпак решает проблему неиспользуемого кода.
Такой код берется очень просто.
Пусть libfoojs умеет делать операции foo и bar.
Но мне нужна только foo. Значит код для бар будет неиспользуемым.
Если говорить про С, то там тоже при линковке избыточный код выбрасывается. У других ЯП, я думаю, ситуация такая же.
Что вы несёте?
Пожалуйста, давайте без хамства.
Анализируйте исходники на здоровье, или вы также сидите и анализируете байт-код джавы после компиляции?
До вас серьёзно не дошло, что речь про проекты, где в открытом доступе нет исходников?
А даже если где-то они и есть отдельно — в браузерном инспекторе (когда они не минифицированы) их читать намного быстрее и проще, чем идти на гитхаб и выкачивать оттуда, либо читать там.
Разница от минификации может быть в несколько раз
После сжатия не может.
пожмет все названия переменных и функций до 1-2ух символов
выделит повторяющиеся паттерны строк в отдельные переменные
Сжатие именно это и делает. Причём не только для имён переменных, а для любых повторяющихся подстрок.
удалит неиспользуемый код
Зачем его вообще добавлять тогда?
много чего еще
Ага, например:
- Усложнит отладку на проде вплоть до невозможности что-либо понять.
- Может сломать релизную сборку своими предположениями об эквивалентности преобразований.
- Замедлит деплой, порой в несколько раз.
- Сделает стектрейсы с прода бесполезными.
Сжатие именно это и делает. Причём не только для имён переменных, а для любых повторяющихся подстрок.
У вас в исходном коде может и не быть много повторяющихся подстрок (названия функций все таки отражают, что они делают и могут быть сильно разными), а минификатор специально заменит почти все функции и переменные на одно-двух буквенные вариации.
Ради простого примера:
function zip(arrays) {
...
}
function split(string) {
...
}
превратиться примерно в
function c(c) {
...
}
function cc(c) {
...
}
Что гораздо лучше сжимается чем исходный код любым алгоритмом сжатия. Причем алгоритмы минификации устроены таким образом, что результирующий код был compression-friendly.
Зачем его вообще добавлять тогда?
Например в зависимости от конфигурации могут получаться разные условия?
Усложнит отладку на проде вплоть до невозможности что-либо понять.
Вообще никак не усложняет отладку, потому что есть source-maps которые позволят вам даже в проде видеть оригинальный исходный код. Вообще не очень понимаю зачем дебажить продакшн, дебажьте дебажную сборку?
Может сломать релизную сборку своими предположениями об эквивалентности преобразований.
Не может (если вы следуете стандарту).
Замедлит деплой, порой в несколько раз.
Зато ускорит скачивание и открытие страницы пользователем в несколько раз. JS это не только скачивание, это еще и парсинг который очень дорогой, и чем меньше кода, чем меньше названия переменных — тем проще и быстрее его распарсить.
Сделает стектрейсы с прода бесполезными.
Смотри пункт про отладку
минификатор специально заменит почти все функции и переменные на одно-двух буквенные вариации
Что даст максимум 10% после сжатия, офигеть какая разница.
Например в зависимости от конфигурации могут получаться разные условия?
Так в зависимости от конфигурации и добавляйте. Зачем добавлять, а потом надеяться, что оно может быть выпилится?
Вообще никак не усложняет отладку, потому что есть source-maps
Судя по этому заявлению вы используете возможности отладчика лишь на 1% возможностей. Ну или просто никогда не отлаживали минифицированный код по сорсмапам. Которых на прод обычно вообще не кладут, что особенно доставляет.
Вообще не очень понимаю зачем дебажить продакшн, дебажьте дебажную сборку?
Потому что бага воспроизводится лишь на проде и нужно понять как воспроизвести её на дебажной сборке. Вы вообще дебагом хоть раз занимались в реальной жизни?
Не может (если вы следуете стандарту).
Простой пример из жизни — пишу ;this.foo;
рассчитывая на сайд эффект в геттере, который протрекает зависимость и перезапустит мой код, когда свойство foo изменится. Минификатор вырезал обращение к свойству, прикинув, что его значение всё-равно никуда дальше не идёт. У меня всё работает, а тестировщики шлют "невозможные" багрепорты. Какой стандарт я нарушил?
Зато ускорит скачивание и открытие страницы пользователем в несколько раз.
При наличии сжатия лишь на жалкие 10-20 процентов, которые никто из пользователей не заметит.
чем меньше кода, чем меньше названия переменных — тем проще и быстрее его распарсить.
Так пишите меньше кода, а не меньше названия переменных — профита будет куда больше.
Смотри пункт про отладку
Вы бы попробовали сначала, прежде чем так уверенно говорить. Сорсмапы работают исключительно в дев тулзах и исключительно постпроцессингом при отображении.
рассчитывая на сайд эффект в геттере
Какой стандарт я нарушил?
Здравую логику. Геттеры не должны делать никаких сайд-эффектов, влияющих на состояние объекта.
А подскажите тогда, как запустить force reflow? Единственный известный мне способ — дёрнуть этот самый геттер с сайд-эффектом (бутстрап, например, дёргает offsetHeight)
Я хотел сказать, что такие штуки стоило бы оформлять в виде функции, а не геттера, ибо от последнего ни минификатор, ни программист не ожидают никаких дополнительных действий, непосредственно влияющих на логику выполнения.
При работе с анимациями на базе CSS3 Transition reflow требуется почти везде
В том же бутстрапе это оформлено как function reflow(element) { return element.offsetHeight; }
, но это всё ещё сайд-эффект на геттере (я не проверял существующие минификаторы, но чисто теоретически шибко умный минификатор может и вырезать неиспользуемый результат вызова reflow(), наверно)
У меня были проблемы почти во всех браузерах, связанные вот с чем: допустим, есть у меня свойство, на нём стоит transition (пусть это transform, делающий движение с небольшим поворотом для эффекта перелистывания страницы-фотографии); я хочу подвинуть элемент, затем скрыть его через display: none, через JavaScript назначить transition-duration в 0, поставить его на место пока он скрыт, и потом вернуть transition-duration обратно. Беда в том, что это всё адски глючит. Если быстро листать фотографии, то можно наблюдать совершенно дикие эффекты — фотография сначала оказывается на 80 процентов от начальной точки (под ней видна следующая, но происходит так, будто 80 процентов траектории мы проскочили моментально), потом делает скачок к начальной точке; иногда получается так, что перелистываемая фотография совпадает с последующей, хотя её src должен обновиться только после завершения эффекта, а никак не во время его.
Опытным путём я установил, что чтобы не было ошибок, надо подождать минимум 250-400 мс после завершения transition перед тем, как менять параметры перехода, и потом поменяв нужные свойства через transform в идеале нужно снова подождать столько же, прежде чем возвращать длительность на место. Приходится делать дикие извраты с вручную подобранными таймаутами, причём в разных браузерах и на железе разной мощности это всё работает по-разному.
Научите, как такое делать правильно :)
Насколько я сам понимаю суть происходящего — без reflow начальное состояние элемента оказывается неопределённым, и если не принудить браузер вычислить стили элементов в начале анимации, то начинаться она будет откуда попало. В случае с display:none начального состояния по сути вообще нет, и никакого transition вообще не будет, пока браузер не просчитает элемент хотя бы раз после выключения none.
Пример: https://jsfiddle.net/83oxepgj/
Общий алгоритм примерно такой:
1) Задать стили начала анимации с transition-duration: 0ms
2) force reflow
3) Задать transition-duration
4) Задать стили завершения анимации
5) [Опционально] Повесить setTimeout на transition-duration миллисекунд (событие ontransitionend не очень надёжно, потому что не сработает, если окажется, что начало и конец совпадают и анимировать нечего)
Другой пример: https://jsfiddle.net/c8d0Ltry/ — без reflow стили начала анимации игнорируются, потому что браузер не успел их учесть и пересчитать всё, из-за чего элемент начинает двигаться с середины, а с reflow браузер вынужден всё пересчитать и поставить элемент на начало, и всё норм
пока браузер не просчитает элемент хотя бы раз после выключения none
Так почему он его не просчитывает после назначения display: block? Кроме того, у меня начальное значение на самом деле ещё как определено — только в CSS коде, а вот конечное я задаю через JS присвоение.
Потому что сама по себе установка display: block не является поводом для reflow — браузер ленивый. А вот попытка получить координаты или размер элемента уже вынуждают браузер не лениться и рассчитать эти самые координаты и размер
Но почему сама по себе установка display: block не является поводом для reflow, я уже не знаю. Может, в стандартах это описано, но не читал
ещё как определено — только в CSS коде
Когда элемент display: none, у него нет ни координат, ни размера — независимо от того, чё там в CSS-коде. И не появится, пока браузер не будет вынужден их просчитать (reflow)
Но почему сама по себе установка display: block не является поводом для reflow, я уже не знаю. Может, в стандартах это описано, но не читал
Видимо, в угоду быстродействию. Я думаю, если у нас display: block у элемента в нормальном потоке, reflow будет (или браузер просто поднимет/опустит нижележащий контент, что намного быстрее, однако если у нас этот элемент ещё и имеет float отличный от none, вот тут уже без перестроения никуда). А тут проблема вся в том, что мы оперируем абсолютно позиционированными элементами (в том моём случае так было, и в этой демке тоже). Их если показать или скрыть — ничего ведь в остальном не поменяется. Я вообще больше удивлён, что происходит при обращении к свойству на чтение… Казалось бы, можно было тупо вернуть последний закэшированный размер :)
Ну и потом — почему разработчикам движков не сделать нормальный метод для такого (который бы делал то же самое, но не выглядел как костыль)? Что-то вроде document.reflow()
UPD: убрал position: absolute, ничего вообще не изменилось.
Я кстати немного «испортил» ваш пример: сделал, чтобы первая кнопка работала несмотря на отсутствие этого приёма (задержка в 20 мс даёт результат, в 10 уже нет), а второй кусок кода тоже порезал, выкинув, казалось бы, довольно критичную часть, позволяющую сделать моментальный возврат шарика — но тем не менее почему-то код продолжает идеально работать (тестировал в Firefox 52 ESR, поскольку в Chrome у меня JSFiddle упорно не хочет работать ни в версии 49, ни даже в версии 54). Возможно, секрет заключается в том, что перепозиционирование происходит тогда, когда элемент невидим (вы писали, что при этом не вообще не активируются transitions)?
jsfiddle.net/4Lfawnqy
Кажется, второй кусок кода продолжил работать, потому что установка display: none сбрасывает элемент в «никакое» состояние и при последующем его снятии браузер оказался вынужден брать translateX(0px), несмотря на ненулевой transition-duration (то есть между display='none' и display='' анимация не работала)
Если заменить display: none на visibility: hidden (когда видимости нет, а координаты с размером всё ещё есть), то второй кусок кода таки сломается
потому что установка display: none сбрасывает элемент в «никакое» состояниеИ это тоже крайне странно. Это с точки зрения рендера состояние, быть может, «никакое». А с точки зрения правил CSS/свойств style стили очень даже назначены… Мне кажется более логичным ваше предположение про то, что пока display равен none, транзишены игнорируются, и поэтому нет никаких задержек на длину перехода.
На самом деле, я сам буквально месяца два назад писал код своего движка, элементы с display: none у меня пропускаются на стадии layout, а элементы с visibility: hidden — только на стадии отрисовки. Я понимаю, почему для элементов с display: none нет рассчитанных размеров — зачем тратить ресурсы, высчитывая их, если это не повлияет на другие элементы, а текущий элемент вообще скрыт. Но в нашем примере речь про координаты, заданные явно, тут размер без разницы.
UPD: хотя в принципе да, вы правы, координаты считаются примерно в том же месте алгоритма, их тоже в этом случае считать незачем.
Кроме того, в середине анимации состояние рендера не соответствует ни начальному состоянию, ни прописанному в CSS-коде, и если вдруг анимацию поменяют в середине, то начинать новую анимацию надо будет с той самой старой середины, так что опираться на CSS-код тоже нельзя
В общем случае (если не указаны top/bottom/left/right) положение элемента даже с position: absolute зависит от соседейРазве? Вроде только от положения ближайшего по иерархии предка с position: relative/absolute. По умолчанию там нули (left, top, bottom, right), то есть левый верхний угол элемента будет в левом верхнем углу этого самого предка. Я не прав?
В Firefox этот пример, однако, глючит) Если открыть инспектор и задать display: inline
для <p>
и потом display: inline-block
для <div class="abs">
, то этот самый abs
останется внизу под <p>
. А если сделать всё наоборот (сперва inline-block
для abs
, потом inline
для <p>
), то abs
переедет вправо) А в Chrome abs
уезжает вправо в обоих случаях
<
br>
блочным элементом с нулевой высотой (потому что поведение похоже), сейчас проверил в Хроме — а он инлайновый, внезапно.То есть его действительно можно невозбранно включать внутрь инлайновых элементов для разбивки на строки. Хотя всё равно в реальной практике я такого ещё не видел, чтобы те же span-ы или что-то подобное содержали внутри
<
br>
. Но в любом случае, это не важно: у нас может быть просто span, естественным образом занимающий несколько строк, и мы имеем право что-то выставить по его нижнему краю с помощью position: absolute.Ну да, теоретически вы конечно правы. Однако вот на практике — представляете, за 8-10 лет ни разу ещё не использовал при вёрстке
position: absolute
не указав обе координаты. Ибо зачем такое может понадобиться вообще? :)Если я понял правильно, при значениях
auto
позиция элемента будет такой же, какой она была бы при position: static
(другое дело, что при расчёте высоты и ширины родительского элемента наш абсолютно позиционированный элемент не учитывается, отсюда и эффект вылезания за нижнюю границу). Кроме того, если добавить третьего потомка с position: static
, то второй наложится точно на него. Отлично.А теперь добавим в самое начало ещё один элемент с
float: left
. Ожидается, что наш абсолютно позиционированный элемент будет выведен там же, где был бы в случае нормального потока (по правому краю float элемента). Ан нет, он наложится прямо на него. Такие дела.Здравую логику.
Нет такого стандарта.
Геттеры не должны делать никаких сайд-эффектов, влияющих на состояние объекта.
Почитайте про реактивное программирование.
это еще и парсинг который очень дорогой
Парсинг (разбор на токены) ни разу не дорогой. Там время пропорционально длине исходного текста. Ну замените вы все имена функций на 1-2 символьные комбинации, и переменные заодно (которые и так часто делают короткими). На сколько сократится объём кода? Что-то мне подсказывает, что даже не в 2 раза. Но даже возьмём, что в 2 — парсинг занимает несколько миллисекунд на современном железе. Ну будет не 4 мс, а 8 мс — разве это смертельно?
Вот кстати пример из жизни, когда минификация не столько помогает, сколько вредит: есть сторонний проект, на нём есть код, использующий новые фичи. Код не работает в одном из старых браузеров. В случае наличия несжатых исходников — можно было бы изучить реализацию и понять, в чём там дело. А так -берём минифицированный код, смотрим, ставим брейкпоинты (с этим тоже бывают проблемы, особенно становится весело когда целевой браузер не умеет ставить брейкоинты в коде, получившемся после обработки PrettyPrint и добавления переносов, то есть переносы добавляются, но только визуальные, брейкпоинт туда не воткнуть), снова смотрим, через 2 часа плюём в монитор и бросаем это гиблое дело.
Сейчас браузер не позволит написать нам ни 1++2 (подразумевая, что второй плюс — унарный плюс), ни 5++a. В обоих случаях парсер выдаст ошибку «Invalid left-hand side expression in postfix operation».
Исходя из этой логики, никаких 5++
-
5 мой движок допускать вообще не должен в принципе (как сейчас не допускается 5+-
5). Да, в текущей реализации это отработает как (5++)-
5 (а может быть выдаст ошибку, надо тестировать — не уверен, что у меня вообще допускаются два оператора, идущих подряд на этапе парсинга токенов). Но если мы хотим другого поведения, надо ставить скобки.P.S. Вообще я понял суть проблемы, перечитав таблицу приоритетов. Создаётся неопределённость — непонятно, у нас унарный плюс, унарный минус и сложение, или постфиксный инкремент и вычитание. Но независимо от того, разрешён постфиксный инкремент на литералах или запрещён (в текущих реализациях он запрещён), запись 5++
-
5 вызовет ошибку, и это совершенно правильно. Другое дело — в текущих реализациях перед литералом можно написать два минуса, и это будет равносильно тому, как если бы не написали ничего (два умножения на -1), а у меня это выдаст совсем другой результат. Но я не очень представляю, зачем писать ровно два (или любое чётное) количество унарных минусов перед числом или переменной. В конце концов, на то что перед переменной это сработает как префиксный инкремент, никто не жалуется?Math.tan(Math.PI / 2)
Точно так же
Math.tan(Math.PI)
не равен 0Ну вот мы и добрались до причины проблемы
В чем проблема то?
что PI/2 в компьютере представить невозможно
Возможно. Вы же понимаете, что для того, чтобы определить константу, совсем не обязательно уметь вычислять все её цифры после десятичной точки?
В чем проблема то?
В том, что тангенс вычисляется абсолютно неверно.
В том, что тангенс вычисляется абсолютно неверно.
Я вам больше скажу, тангенс в компьютере вычисляется неверно для всех чисел. Вы также будете будете вводить интервалы для PI/3, чтобы получить «ровно» корень из трех?
Ваша аппеляция к «а давайте тогда сделаем в Pi/3 ровно корень из трёх» имеет не особо много смысла хотя бы потому, что и сам корень из трёх имеет весьма приближённое значение, и при возведении в квадрат не даст 3.
Ваша аппеляция к «а давайте тогда сделаем в Pi/3 ровно корень из трёх» имеет не особо много смысла хотя бы потомуСами придумали, сами опровергли
Сами придумали, сами опровергли
Это вы предложили про корень из трёх, я-то что?)
Вы написали лишь одну причину.
Получать бесконечность там, где должна быть бесконечность — это может и правда одна причина. Но как бы и её очень даже достаточно.
Точка экстремума, опять же (Pi/3 таковой не является).
Это вы предложили про корень из трёх, я-то что?)Пруф или лжец.
Я вам больше скажу, тангенс в компьютере вычисляется неверно для всех чисел. Вы также будете будете вводить интервалы для PI/3, чтобы получить «ровно» корень из трех?
Окей, вы не предложили, а задали наводящий вопрос. Но из этого вопроса я заключил, что вы предлагаете или отказаться от всех корректировок, или добавить корректировку и для Pi/3. Разве вы не это имели в виду?
Но теперь вы возвращаете совершенно некорректное значение для углов, близких к Pi/2.
Причем эта бесконечность отравит все последующие вычисления, где-то мутировав до NaN, и в итоге все будет очень плохо. При чем программист-то этого, руководствуясь стандартом, не ожидал.
Да, это плохо, но имхо не катастрофично.
Впрочем, я сегодня посмотрел — похоже, я вас всех дезинформировал, прошу прощения. В моём коде применён был иной подход, анализируется именно получившееся значение нативной функции tan из Java. То есть точки, отличные от Pi/2, не пострадают.
Смотрите, бесконечность хороша тем, что операции с ней безопасны. К ней можно прибавить число, её можно умножить на число. Можно даже умножить бесконечность на бесконечность. И при этом всё будет замечательно (пока не начнём делить, тогда получим NaN). Но переполнения в этом случае точно не случится.
Не знаю, что там написано в стандарте на этот счёт, но хороший программист, имхо, прежде чем дальше с этим результатом что-то делать — поставит проверку на допустимость такого действия. Случай с бесконечностью в результате «ловить» гораздо красивее, чем случай с числом 16331239353195370, вам не кажется?
Предположим, я — прикладной программист на JavaScript. Я хочу проверить, получилась ли у меня бесконечность после вычисления тангенса. В текущей реализации (возьмём имплементацию Chrome) у меня есть три варианта действий:
1. Сверяться с неким очень большим целым числом, обнаруженным при вычислении тангенса Pi/2 эмпирически. (где гарантия, что однажды оно не поменяется? оно даже не равно максимальному целому в рамках какой-либо длины).
2. Считать тангенс Pi/2 прямо перед проверкой. Выглядит не очень, да и с точки зрения производительности — такое себе.
3. Поставить эту проверку до вычисления тангенса. В таком случае мы получим код вроде
if (Math.abs(th - Math.PI/2) < 0.0001) { ... }
Окей, третий вариант неплох. Но зачем заставлять программиста писать это каждый раз?
В моей реализации эти действия делает интерпретатор (программисту ни о чём беспокоиться не нужно), и в случае аргумента, близкого к Pi/2 вернётся ровно то, что программист ожидает получить (плюс бесконечность).
Единственное что нужно доработать — всё-таки стоит создать две особых сущности для плюс бесконечности и минус бесконечности, сделать их полями Number, и возвращать их (а ещё научить с ними работать функции isNaN и isFinite). Потому что сейчас у меня возвращается NaN, а это не совсем идеально — хотя бы тем, что нельзя проверить знак результата.
В моей реализации эти действия делает интерпретатор (программисту ни о чём беспокоиться не нужно), и в случае аргумента, близкого к Pi/2 вернётся ровно то, что программист ожидает получить (плюс бесконечность)
Окей, ваш интерпретатор готов гарантировать (я ожидаю получать правильный результат), что
(tan(PI/3))^2 == 3? Сомневаюсь, а то что
(tan(2*PI/3))^-2 == 3? Я могу таких примеров бесконечное множество приводить
Забудьте про тангенс, введите в консоль Хрома
Math.sqrt(3) * Math.sqrt(3)
. Получается 3? У меня нет :)P.S. На самом деле, из-за особенностей вычислительных алгоритмов разных функций, у нас не будет выполняться
Math.tan(Math.PI/3) == Math.sqrt(3)
.Я посчитал разность, получилось -4.440892098500626e-16. Но с этим ничего нельзя поделать, тут и мой интерпретатор ничего не предложит. С этим не справится ни Java, ни мат. библиотека Chrome, к сожалению. Тут уже нужен совершенно специальный мат. софт.
Если вы ожидаете, что tan(PI/2) должно возвращать бесконечность в компьютере, то я например ожидаю, что tan(PI/2-epsilon) не будет возвращать бесконечность, как вы будете решать эту «проблему»? Ведь в вашей имплементации все числа близкие к PI/2 будут давать бесконечность?
PI/2 тоже имеет «некоторую степень точности» и tan имеет «некоторую степень точности»
Просто проблему, которую описал я, решить можно (трактуя Pi не как приближённое float/double значение, а как особую сущность). А проблему, поставленную вами, решить крайне трудно (и не факт, что это нужно вообще для JS движка).
Если вы ожидаете, что tan(PI/2) должно возвращать бесконечность в компьютере, то я например ожидаю, что tan(PI/2-epsilon) не будет возвращать бесконечность, как вы будете решать эту «проблему»? Ведь в вашей имплементации все числа близкие к PI/2 будут давать бесконечность?
Согласен, это косяк. Но всё же шансы, что вы будете делать какие-то осмысленные вычисления с числами, очень близкими к Pi/2 (где вам нужны будут реальные очень большие тангенсы как они есть), довольно мала. Я вижу один вариант такого применения — для сравнения исходных аргументов. Но почему бы просто не сравнивать сами аргументы? Они тоже неплохо сравниваются.
Шансы того, что кто-то будет делать осмысленные вычисления, где понадобится точное значение тангенса пи/2 ещё меньше.
Вы к тому, что просто вместо вычисления тангенса можно сразу записать в коде его результат через Number.POSITIVE_INFINITY? Ну в целом — да, согласен. Но всё же иногда это может быть нужно. Вот вам пример: есть у нас угол, кратный Pi/4 (или Pi/8, Pi/16 и так далее). Происходит умножение, и после него мы считаем тангенс. В этом случае «захардкодить» результат нельзя.
Единственная осмысленная операция с ним, это деление на него, но тут достаточно очень большого числа (которое и выдаёт имплементация в chrome) чтобы получить число достаточно близкое к нулю.
Почему только деление? Мало ли, что пользователь захочет сделать потом. Вот захочет он умножить на число, большее нуля, например. В случае, если у него бесконечность — он просто отловит этот случай и не будет умножать (или умножит и получит то же самое, в Chrome это отлично работает). А умножив результат тангенса из Chrome? В лучшем случае — просто непонятное больше число. В худшем — переполнение.
Предположим, я — прикладной программист на JavaScript. Я хочу проверить, получилась ли у меня бесконечность после вычисления тангенса
И зачем ЭТО прикладному программисту на JS?
Вы лучше скажите, зачем прикладному программисту тангенсы чисел очень большой величины, но конечные. Если мы что-то строим на плоскости, например — то все углы близкие к 90 градусам можно считать равными 90 градусов — всё равно у нас пиксельная сетка, и размеры дисплея не позволят нарисовать такой угол так, чтобы он не был идентичен вертикальной прямой, а если и позволят — будут большие проблемы в виде ступенек или размыленности.
в случае аргумента, близкого к Pi/2 вернётся ровно то, что программист ожидает получить (плюс бесконечность).
Почему плюс, а не минус? Тангенс в этой точке имеет разрыв и не определён, так как слева он уходит в плюс бесконечность, а справа — в минус. Так что возвращаться тогда уж должен NaN, но он с прикладной точки зрения бесполезен чуть менее, чем полностью.
Кроме того, операция инкремента по стандарту требует lvalue, а литерал — это rvalue
Ну, тот же IE в своё время многое делал не так, как указано в стандартах. Правда, это для него плохо кончилось)
Между прочим, в стандарте для функции isFinite сказано: «If num is NaN, +∞, or -∞, return false».
Так в том-то и дело: там плюс бесконечность, а возвращается true.
Так вот, внимание — isFinite(tan(Math.PI / 2)) возвращает false!
Простите, но я вот решил проверить и Хром говорит, что вы обманываете нас.
isFinite(Math.tan(Math.PI / 2)); // true
На самом деле и функция проверяет другое, и ответ другой. Но от этого он не становится правильным.
Вообще, если говорить об альтернативных движках, то NetSurf на первый взгляд выглядит поинтереснее сабжа: свой HTML-парсер есть, CSS-парсер тоже есть (соответствие стандартам не проверял), JS-движок Duktape с последними фишками ES2015+. Затыки, естественно, на самом сложном: рендер (в отличие от сабжа) есть и рисует примерно на уровне IE8 (лично мне этого достаточно, у меня успешно получается верстать под NetSurf), а вот полноценного DOM API и событий (ещё) нет, из-за чего JS бесполезен, несмотря на его наличие
В качестве инструмента для рендеринга будете использовать Skia, Cairo, AGG или что-то самописное?
Мало того что это абсолютно неэффективно, так еще и во многих случаях может ломать код.
Например здесь сложно сказать, что произойдет после выхода из функции так как по факту объект str будет уничтожен сразу после выхода из функции.
Token* fromMisc(DOMString str)
{
MiscToken* misc = new MiscToken();
misc->data = str;
return (Token*)misc;
}
Token* fromText(DOMString str)
{
Text* text = new Text();
text->text = str;
return (Token*)text;
}
Это работает только потому-что у объекта DOMString нету деструктора! В итоге имеет на каждый чих копирование огромной строки и бесконечно большую утечку памяти.
Лучше наверное все таки использовать? (ну и конечно же написать нормальные деструкторы)
const DOMString& str
Для вашего примера с временными объектами придумали move-семантику.
Тем не менее вопрос об абсолютно неэффективной работе со строками и постоянным копированием (даже в тех функциях происходит два копирования которые можно, и нужно избегать) остаётся открытым
— эта самая строка в ходе парсинга и разбора не должна меняться — следовательно она константа
— использований метода типа fromMisc(«смотри, ма, я временный объект») не будет, так как это не имеет смысла (все таки кто из головы в коде будет придумывать DOMString?)
На мой взгляд нормальной реализацией тут было бы просто написать обертку над const char * и запретить вообще любое копирование и перемещение (=delete). Использовать const DOMString& и проследить чтобы время жизни объекта совпадало бы с вызовом функции парсинга. Если уж хочется сохранять какие то куски строк в токенах как делает автор, то можно оставить возможность отдавать константные слайсы этого DOMString (без выделения новой памяти).
Если юз-кейс отличается от описанного выше — легче использовать std::string
Просто, действительно выглядит пока так что автор замахнулся на задачу, для которой ещё не созрел. Однако, в любом случае это будет отличным опытом, и накидываться не нужно — так никто этого и не делает.
Если да, то пилите! это годное дело.
Точно помню, старый движок opera работал на eeepc900 вполне сносно, когда как то же веб-приложение на последнем firefox (буквально в этом году проверял, жаль железка сломалась) тормозило безбожно.
Между прочим, такой проект был бы оправдан как замена тяжелому electron, а то что ни проект так таскают с собой 60мб хромиум (в установщике) и 30-50 мб оперативки минимум на одно окно приложения и мегааппетиты на просто ui.
p.s. постарайтесь ограничивать функционал там где это оправдано именно для скорости работы движка, если что, популярные фреймворки javascript для веб можно в будущем допилить до поддержки нового движка…
Да, с вероятностью 99% этот проект будет заброшен, но свою задачу он выполнит. К окончанию школы у человека будет нехилый фундамент прикладного программирования.
Ибо одному можно создать каркас (то самые 90% задачи, которые пишутся за 10% времени), но чтобы из этого получился браузер — нужен труд десятков людей.
Вот как их предполагается привлекать?
P.S. В общем я крайне положительно отношусь к перспективам FlightBlaze и крайне отрицательно — к перспективам описываемого движка.
Дело в том, что я изначально поставил задачу написать браузер, который будет корректно работать под Windows XP и выводить красивый, резкий текст. К сожалению, опыт показал, что при использовании Swing сделать это можно только используя «нативные» JLabel, но никак не низкоуровневыми методами вывода текста на графический контекст типа drawString. Однако такой подход не позволял отсекать содержимое при overflow: hidden: панели-слои у меня были неограниченного размера, и включение лейблов в эти панели никак не позволяло их обрезать. Тогда я применил комбинированный подход, выводя текст в менее чётком варианте только тогда, когда его реально нужно обрезать (при overflow равном scroll или hidden). Но проблема в том, что при наличии множества контекстов наложения с разными z-index при изменении практически любого z-index у элемента внутри одного из контекстов придётся всё перерисовать, применив новый порядок наложения.
У меня возникли какие-то проблемы, и я не смог заставить работать штатный механизм z-order в Swing (фрагменты текста-то у меня через JLabel сделаны!) иначе как в момент добавления элемента в контейнер. А при каждой смене z-index элемента удалять и по новой добавлять всё — безумно дорогая операция. Так что увы…
Для работы z-index нужно, чтобы каждый элемент рендерился на своём слое
О, если бы всё было так просто. Объединение в слои как раз и придумали затем, чтобы не создавать на каждый чих отдельного слоя. Почитайте раздел «Краткая история отрисовки и компоновки» в статье habr.com/post/340176. Кроме хорошего объяснения в статье есть хорошие узнаваемые картинки от Лин Кларк :)
>Java в этом плане очень сильно отстает
Вот так откровения. Вообще говоря расклад по скорости такой: 1. плюсы 2. жабка 3. раст.
Речь не про микробенчмарки, а большие проекты. Хотя какие большие проекты у раста? Сферический тузик в вакууме, всех порвал… в теории.
Java быстрее раста? какие-нибудь ссылки можно?
«Хотя какие большие проекты у раста?»
Не согласны? Ну давайте вы ссылки на аналоги Cassandra, Neo4j, Lucene, JBOSS и тд
Когда такое появится, тогда и можно будет говорить про скорость не в микробенчмарках.
В целом, уверен, что аналог более-менее грамотно написанного софта, писанного под JBOSS, на Расте будет из костылей, велосипедов, г и палок. С соответствующей производительностью.
1) Servo сойдет?
2) Я понял вашу точку зрения. Но в таком случае производительность раста и джавы не сравнимы вообще, и любой их порядок, в т.ч. ваш, некорректен.
Неубедительно вчера написал. Вообще говоря, представление о низкой скорости раста у меня сложилось глядя на масштабные бенчмарки с несколькими языками. По тестам выходит что раст телепается где-то на уровне go и сильно отстаёт даже от плюсов, не говоря о анси си. Жабка, как известно, из «второсортных языков» таки самая быстрая. Повторяюсь, речь не про микробенчмарки, а более-менее большие проекты.
Гуглить GraalVM nativeimage. Не быстрее ассемблера, конечно ) Но при грамотном подходе не медленнее Си и гораздо удобнее в разработке и поддержке.
Отсутствуют такие фичи, как динамическая подгрузка кода и финализаторы.
Т.е. управлять ресурсами предлагается вручную?
Насколько я вижу, GC никуда не девается.
Интересно, как Java с GC и без C++-style шаблонов может работать на уровне плюсов.
Нет. В Java есть AutoCloseable, финализаторы в Java это про другое их давно никто не использует. Динамическая подгрузка это вы наверное про Dynamic Class Loading?
>Насколько я вижу, GC никуда не девается.
Да, она на месте.
>Интересно, как Java с GC и без C++-style шаблонов может работать на уровне плюсов.
Элементарно, я поэтому и написал при «грамотном подходе». Например, один из подходов использовать пул объектов, там где очень часто нужно удалять и создавать новые объекты. Или вручную размещать структуры в массивах, взяв управление по размещению/освобождению данных в свои руки (но это больше про индексы).
Еще можно использовать RingBuffer и т.д. Опять же в последнее время в Java популярна off-heap техника, когда можно управлять памятью вручную вне владений GC.
Такие подходы вполне можно использовать в узких местах при написании браузера. Поэтому не вижу ничего страшного сделать новый браузер на GraalVM с nativeimage.
- То есть предлагается писать собственный jemalloc?
Давайте на примере (псевдокод)
class CP { HANDLE h; CP(options) { h = CreateProcess(options.path, options.argv, options.env, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); } // some functions like get_stdout() ~CP() { CloseHandle(h); } }
Типичный RAII — в конструкторе выделяем ресурс (в д.с. дочерний процесс), в деструкторе освобождаем.
Таким образом я могу писать код вида
ChildProcess cp("ls", {"-a"}, {});
print(cp.get_stdout());
//resources are cleaned automatically
Как такое переносится на джаву? Для простых случаев кажется есть try-finally, а для более сложных?
Костыль тот ещё, но… 98% потребностей закрывает. А RIAA закрывает 99%, всё равно не 100%, так что, в общем, не бог весть какая проблема…
Нет. Основную работу делает GC. Сейчас есть GC с гарантированными 10 ms паузами. Но там, где есть узкие места, можно вручную выделять и освобождать память. Создав узкоспециализированный оптимизированный под данную задачу аллокатор.
>Как такое переносится на джаву?
>для более сложных?
Для более сложных управляете вручную или полагаетесь на IoC (dependency injection). Последнее решение очень популярно в Java. IoC автоматически загружает и выгружает (при завершении треда или по другим причинам) объекты, поэтому может, в том числе, выполнять функции деструктора.
- Тред вроде бы начался со сложных RAII объектов, которые не могут управляться обычным GC, т.к. он не дает гарантий по вызову деструктора. Например, вышеупомянутый класс CP, если управлять им с помощью сборщика мусора, при активном использовании просто забьет таблицу процессов. При этом сборщик мусора даже не попробует начать почесываться: память свободна на 99,9999%.
- По-моему, DI не требует использования DI container'а (вы же его имели в виду?).
- А какие еще есть причины, кроме завершения потока? К примеру, выход объекта из области видимости?
В джаве другой подход. Например, в JDK есть Process API, который не требует очистки ресурсов пользователем при создании аналога CP в джаве. Т.е. вы просто запускаете нужный вам процесс и не паритесь за его ресурсы.
Если копнёте Process API, то увидите, что всё построено вокруг асинхронных проверок завершения процесса. Буквально в пул тредов добавляется Runnable проверяющий завершение процесса и очищающий его ресурсы. Сохраняя его out до выхода объекта из области видимости GC.
Такой подход отчасти позволяет писать примерно так process.onExit().thenAccept(p -> ...)
У меня к сожалению нет опыта разработки на С++, чтобы показать как схожие проблемы решаются на Java. Но думаю выше приведенный пример отчасти показывает различие в подходах.
>А какие еще есть причины, кроме завершения потока?
Вылет по эксепшену. DI не настолько круты, чтобы контролировать выход объекта из области видимости. При желании, конечно можно сделать троллейбус из буханки, но не для этого задумывались DI.
- Ок. Я привел плохой пример, т.к. сразу после завершения дочернего процесса уже можно сделать всякие CloseHandle.
- Тогда давайте еще более натянутый пример:))
класс KVM (KuchaVM) — поднимает 100500 виртуалок в облаке и выставляет что-то вроде тредпула наружу. process.onExit().thenAccept(p -> ...)
В плюсах можно писать точно так же, если предусмотреть что-нибудь вродеstd::future<long long> on_exit()
(ни разу не писал такое, поэтому про детали говорить не могу).
- Ну вот. DI не позволяют сконструировать замену RAII.
- Кстати, часто ли вы встречали сложные лафйтаймы объектов, которые нельзя выразить с помощью unique_ptr / shared_ptr?
Вручную пишите выделение и освобождение ресурсов. Запихивать такие вещи в деструкторы это путь к не очевидным ошибкам. Отчасти, начинаю понимать, почему в Java метод finalize начиная с 9-ки стал deprecated.
Чем больше в ЯП неявного поведения, тем сложнее такой код поддерживать.
>Кстати, часто ли вы встречали сложные лафйтаймы объектов, которые нельзя выразить с помощью unique_ptr / shared_ptr?
Вы не понимаете сути проблемы. GC позволяет лишний раз не думать и увеличивает скорость разработки. Делает код проще, что означает возможность рефакторинга и простой доработки кода в будущем.
Ручное управление памятью это прошлый век. Такой подход необходим только в узких местах или в очень нишевых областях. В прикладном ПО можно без опасений использовать современные GC. Затыки по перформансу будут совсем в других местах.
Нарпример, вот код который я иногда пишу:
void dfs(const vector<int>& g, vector<bool>& used, int v) {
//...
}
int main() {
//read
dfs(g, used, 0);
}
Без никакого GC.
GC позволяет лишний раз не думать и увеличивает скорость разработки. Делает код проще, что означает возможность рефакторинга и простой доработки кода в будущем.
Где вы тут видите необходимость думать над очисткой? ее тут нет. При выходе из ф-ции main будет вызван деструкторы у g и used, и вся память будет освобождена.
Так же как и в варианте с GC. Но у меня есть деструкторы а у вас нет.
Получается, что как только появляется объект, потребляющий внешние ресурсы (неуправляемая память, файлы, процессы, виртуалки в облаке), вам необходимо использовать какие-то новые конструкции(try-with-resources либо вообще ручное управление foo.close(), что имхо не оч), а мне — нет. Если я написал самый лучший в мире сет, который не делает утечек, то я могу спокойно положить в него объекты вышеупомянутых CP & KVM. А вам придется добавлять костыли для поддержки IClosable. Кстати говоря, есть ли они в стандартной библиотеке? Можно ли сделать ArrayList таких объектов, чтобы он корректно обрабатывал .close()? (НЯП джаву, ответ — нет).
Ну здесь нет, а где-то есть. Еще раз GC позволяет делать код проще. Упрощает рефакторинг и долгосрочную поддержку. Иначе GC ЯП не стали бы настолько популярными.
>Но у меня есть деструкторы а у вас нет.
Я вам еще раз скажу — неявное поведение это путь к неявным ошибкам и сложностям в рефакторинге. Сложности в чтении и поддержки кода.
Через #close метод я смогу найти очистку ресурсов в коде с помощью IDE. Очистка через деструктор этого не позволяет, тем самым усложняется понимание кода, что ведёт к ошибкам.
Я знаю один объективный аргумент — снижается порог входа. Какие еще?
Я могу сказать ровно то же самое что вы сейчас сказали, и показать что самое лучшее — malloc / free. Потому что все явно, везде можно всюду перейти, и т.д.
Вы не ответили на один из моих вопросов. Сколько строк кода нужно в джаве чтобы освободить список файлов?
Почему вы считаете логичным, что один ресурс, т.е. память, управляется GC, а остальные — почти вручную (путем .close())?
Деструкторы тут более консистентны.
— упрощается рефакторирнг
— код легче читать и поддерживать
— увеличивается скорость разработки
— уменьшается кол-во ошибок с выделением/освобождением памяти
>Я могу сказать ровно то же самое что вы сейчас сказали, и показать что самое лучшее — malloc / free.
Вы не сможете с помощью этого решения найти в коде выделение памяти для конкретного объекта. Т.е. у вас в методе есть ссылка и IDE не скажет вам где для неё выделялась память и где она освобождается.
Если эта проблема решится хотя бы на уровне IDE, то я только за malloc/free и в тот же день буду с пренебрежением относиться к ЯП с GC.
Более того я периодически думаю насколько возможно сделать подобное решение. Но пока нет времени заняться этим вплотную.
>Вы не ответили на один из моих вопросов. Сколько строк кода нужно в джаве чтобы освободить список файлов?
Если для вас важны строки кода, а не простота чтения и поддержка кода. То мы с вами живём в разных вселенных. Значит вы еще не сталкивались с легаси и объемными кодовыми базами.
>Почему вы считаете логичным, что один ресурс, т.е. память, управляется GC, а остальные — почти вручную (путем .close())?
Потому что это хорошо работает. Если у вас потекли объекты, то хрен с ними, обычно это не критично и приложение может продолжать работу.
Но если у вас потекли ресурсы, хуже того вы по ошибке что-то не то снесли. То пользователь будет не в восторге.
Он учитывает любую вашу ошибку.
Например, вы забыли поставить кавычки, набирая атрибут
Движок вас поймет, есть значение атрибута написано без пробелов
Вы можете не закрывать тег, когда это не обязательно
История ничему не учит? Опять на те же грабли наступать?
Хотите повторить судьбу IE?
Вы можете не закрывать тег, когда это не обязательноНеужели вы стимулируете криворуких макак? Есть прекрасный XHTML 5 — фичи HTML и строгость и расширяемость XML! Чего народ так не любит XHTML? Появление XHTML 1.0 я воспринял как праздник! А массы не взлюбили, теги им закрывать лень!
Все как то забыли, почему создавались такие языки разметки как xml — чтобы быть human readable, это первопричина, а так как используют html в основном люди (как разработчики) так и смотерть нужно на их потребности и удобство… Если не закрывать теги не проблема для парсера — то почему нет? это ведь удобно!
p.s. если вам нужна строгость, то я за реализацию бинарного стандарта, в который будет проводиться компиляция на этапе деплоя веб-приложения на сервер… как минимум это будет эффективнее работать на уровне веб-браузеров, особено если стандарт будет максимально строгий, и лишен исторических наслоений.
Тем не менее даже в последней спецификации HTML 5.2 (2017 год, однако) посвящён целый раздел XML-синтаксису: https://www.w3.org/TR/html52/xhtml.html
И цитата из этой спецификации:
This specification defines the latest version of the XHTML syntax, known simply as "XHTML".
А нюансы парсинга кавычек можно всегда подправить, это мелочи.
* ОС — прослойка между железом и юзерспейсом. Юзерспейс можно придумать любой, а вот железо — ой. Делай что есть в реальном мире.
* Браузеры — надо следовать стандартам. Огромным.
В языке программирования же всё предельно просто — как придумаешь, так и будет. Так что для «попробовать свои силы» — язык программирования самый подъёмный. На выходе будет что-то, что будет работать. Удобно или нет — вопрос открытый.
Каждый программист должен в жизни попробовать написать ОС, браузер, или, на худой конец, язык программирования.
При этом — насколько он хорош как программист, определяется пониманием момента, когда надо остановиться. Тут как в фотографии — передержка гибельна.
From: torvalds@klaava.Helsinki.FI (Linus Benedict Torvalds)
Newsgroups: comp.os.minix
Subject: What would you like to see most in minix?
Summary: small poll for my new operating system
Message-ID: <1991Aug25.205708.9541@klaava.Helsinki.FI>
Date: 25 Aug 91 20:57:08 GMT
Organization: University of Helsinki
Hello everybody out there using minix –
I’m doing a (free) operating system (just a hobby, won’t be big and
professional like gnu) for 386(486) AT clones. This has been brewing
since april, and is starting to get ready. I’d like any feedback on
things people like/dislike in minix, as my OS resembles it somewhat
(same physical layout of the file-system (due to practical reasons)
among other things).
I’ve currently ported bash(1.08) and gcc(1.40), and things seem to work.
This implies that I’ll get something practical within a few months, and
I’d like to know what features most people would want. Any suggestions
are welcome, but I won’t promise I’ll implement them
Linus (torvalds@kruuna.helsinki.fi)
PS. Yes – it’s free of any minix code, and it has a multi-threaded fs.
It is NOT protable (uses 386 task switching etc), and it probably never
will support anything other than AT-harddisks, as that’s all I have :-(.
Интересно, что бы ему написали комментаторы с хабра?
Наверно, что-то вроде этого
И да, в свое время я действительно сделал собственный парсер HTML (с обсчетом геометрии), очень даже работающий. Именно полученный опыт помог принять правильное решение на этапе обдумывания рендера и DOM.
Кроме того, крайне важен фактор исторического момента. Открыть что-то новое в математике триста лет назад было несравнимо проще, чем сейчас. И браузер с осью 25 лет назад были гораздо проще нынешних (хотя конечно всё равно сложны).
Насчет сложности — в 1991 году все еще сидели под однозадачным ДОС. Даже Windows 3.1 еще не появился. Не было еще виртуалок и эмуляторов. Линус тогда замахнулся на архисложную по тем временам задачу. Но он правда выкатил Линукс с уже работающим башем и gcc. Может поэтому и взлетело.
Вот если взять современные инструменты и писать под эмуляцию тогдашнего железа (используя QEMU, например) — вот тогда эта задача будет простой…
А если вы не про PC, то а про какую нибудь ARM-железку типа Raspberri Pi, то там процессор вообще запускается операционкой для GPU! От которой ни документации, ни исходников нету!
#include <efi>
int main(SystemTable* systab, Handle image_handle) {
InitializeLib(systab, image_handle);
Print(L"Hello, world!\n");
}
Как-то так. Вроде без legacy костылей.
Может поэтому и взлетело.Ровно потому и взлетело. Весь userspace у него уже был — его задачей было переписать только ядро.
Тоже та ешё задачка для студента, но… в человеко-год он уложился. Тут же делается попытка переписать что-то, что в базовом варианте никому не нужно (и, собственно, пишется куда быстрее, чем за год), а небазовом — требует очень много человеко-лет (потому что нет такого «удобного» деления на части — UNIX состоял из отдельных относительно небольших частей, а вот современный браузер — это монстр, где в одном бинарнике засунуты сотни компонент)
Что действительно кажется интересным, так это эксперименты с sax вместо dom. Или, например — использованием собственного файла подкачки, с возможностью ограничить потребление памяти(вполне реализуемо на всех основных платформах).
Ибо на данный момент, самое узкое место в браузерах — это всё же память, которая потребляется немыслимыми объёмами.
Лично я бы смирился даже с определёнными лагами при загрузке и исполнении js, в пользу браузера который жил бы в одном гигабайте памяти, а не в 6-8, как лидеры рынка.
… так это эксперименты с sax вместо dom
В текущих реалиях это равносильно отключению JS: множество сайтов перестанет нормально работать. Вы этого можете достичь и обычным отключением JS. Впрочем не уверен, что все браузеры при этом будут жрать меньше памяти)
Я плаваю в вопросе, но со стороны, кажется, что, можно держать в памяти только "горячие" участки dom, а остальное можно держать в подкачке. Разница с системными механизмами подкачки должна оказаться вполне значительной, особенно, учитывая распространённость ssd.
Если ещё пофантазировать — страницы могли бы содержать заголовок манифеста, с профилем обращений к dom, для браузеров, которые такое поддерживают.
Я заглянул в репозиторий на github и в несколько кликов попал на код класса DOMStringMap. Вы в статье пеняете на различные типы умных указателей, но в вашем коде реализуете map обычным массивом, и вместо логарифмической сложности ищете ключ линейно. Более того, вы итерируете вектор по обычному индексу, хотя итератор позволяет не производить лишних операций вычисления адреса. Оверхед неправильного выбора часто используемого алгоритма будет на порядки выше оверхеда умных указателей, не котороя уже о том, что использование обычных указателей в сложном коде легко приводит к нестабильности кода. И в других местах вы делаете огромное количество ошибок С++, которые влияют либо на скорость, либо на простоту/расширяемость/поддерживаемость, либо на надежность кода.
https://github.com/FlightBlaze/Newtoo/blob/master/modules/dom/reflect/DOMStringMap.cpp
Во-вторых, вы когда преобразуете kebab-case, копируете строки много раз. Можно этого избежать, если заранее подсчитать количество заглавных букв, выделить память, а потом копировать из исходной строки в новую по кусочкам, вставляя разделители. Если эта функция вызывается часто, а она таки вызывается часто, то это в перспективе очередной оверхед.
И в-третьих, я пощелкал по нескольким файлам, и буду откровенен, у меня есть предположение, что ваш DOMStringMap не реализует сложный функционал, но глядя на заголовки, я не могу понять, зачем он нужен. Кстати, он не map, а view, потому что предоставляет другой интерфейс к значениям в NamedNodeMap, но зачем в свою очередь нужен тот, я тоже не очень понял. В нем еще есть проблема с владением укателем на атрибут.
Он в свою очередь тоже view, но имеет интерфейс map, и реализован вектором, что порождает проблемы скорости, о которых я писал.
И еще момент. Если вы реализуете контейнеры, то очень полезно сохранять у них стандартный интерфейс с итераторами, функциями begin(), end() и т.п. Это позволяет легко применять к ним алгоритмы стандартной библиотеки и не только их.
есть очень много типов умных указателейи ссылка на описание двух типов и одного вспомогательного класса. Это насторожило. Но когда я дочитал до момента, что деструкторов нет, а сборщик мусора планируется писать «потом», то даже как-то любопытно стало. Ну хорошо, хочется GC(и скорости), но зачем тогда C++? Ведь деструкторы считаются самым главным преимуществом C++ над C.
Если говорить об умных указателях из C++ стандарта (webKit исторически использует свои, видимо, но суть дела это не меняет), то отверхеда от использования умных указателей — собственно почти нет. unique_ptr так вообще, в памяти даже занимает ровно столько же, сколько и обычный сырой указатель. shared_ptr — в памяти чуть больше, но в плане производительности «дороговатая» там только операция копирования, т.е. нужно учитывать возможность мультитрединга, а разыменование — копеечная операция, не отличающаяся от доступа к сырому указателю. Чуть дороже всякие операции блокировки weak_ptr-ов, но опять же не принципиально.
И чем вы собственно собираетесь заменить умные указатели? Очень сомневаюсь что работая с сырыми указателями вы сможете избежать многочисленных падений и утечек памяти.
Но поскольку моей задачей было сделать «хоть какой-то браузер», а не «лучший браузер», то тормоза анимаций, особенно если они не сильные — побоку :)
Конкретно у меня попытки реализации в другое упёрлись — в странности джавы при попытке назначить z-индексы слоям через нативный механизм, то есть ничего просто не работало…
P.S. вообще говоря, если анимаций на странице не очень много, сильно тормозить не должно, растровые буферы можно в любом случае кэшировать в оперативной памяти. Тут ещё имеет значение фреймрейт анимации — чем больше фреймрейт, тем больше памяти жрёт и тем чаще надо обновлять картинку.
P.P.S. На сколько я знаю, для ускорения вывода графики применяется очень простая инструкция — BLIT PIXEL (читал в статье от Oracle о Java 2D). Там всего 3-4 варианта реализации, и если отбросить «продвинутые» — то останется вообще один (этот один поддерживается вообще любыми видеокартами любой степени давности, и можно ограничиться им). Какие тут могут быть баги, с которыми непросто справиться даже Гуглу?)
Идеология Newtoo — показать страницу быстрее, чем остальные.
Это выглядит не как идеология, а как цель. Будем надеяться, что это единственная «путанница в головах», и проект даст даст выхлоп!
Как работа для прокачки кругозора — найс. Но не стоит надеяться на успех мероприятия. Парсер это самое простое. Но и там горизонта пока не видно. JavaScript двигло, если и там ты будешь свой велик делать, отнимет огромное количество времени. Рендер,… сдается мне, что еще больше. Тем более поддержка WebGL и анамаций. За это время твой проект устареет. Но даже это не все. Б — БЕЗОПАСНОСТЬ.
Браузер давно перешагнул себя как приложение. Он стал скорее ОС. Не зря появился такой проект как Chrome OS. А интеграция браузеров с сервисами вендеров стала ключевой в их выборе. Например, WebPUSH, маркеты.
В общем, для познания мира изнутри, проект ценен для личного развития. Но я бы рекомендовал фокус сузить. Это позволит достигнуть действительно ценного результата за вменяемый срок.
Хорошим примером того, как надолго может всё это дело растянутся, является sciter.com.
Там схожая ситуация: проект делается одним человеком. Стоит отдать должное — библиотека сделана очень хорошо. Подтверждение тому список клиентов. Цель проекта правда немного другая — GUI для десктоп-приложений на основе HTML вёрстки. Там и CSS, и собственный scripting есть, можно и собственный backend на С++ писать. Исходников забесплатно к сожалению нет, но зато есть бесплатная возможность использовать всё это дело в коммерческих проектах.
Да, и пишется всё это уже много много лет.
1. Я использую в повседневной работе Chrome 45, в нём всё более-менее норм работает.
2. Есть Advanced Chrome, в котором использованы фрагменты кода версии 54, это даже ещё более свежий браузер чем Chrome 49. Работает он шустро, там нет ненавистного мне MD, там работает переход назад по Backspace без установки расширения, в общем, всё шикарно там. Даже шрифты чуть чётче благодаря тюнингу Skia от автора сборки.
Просто не люблю быть привязанным к одному единственному продукту, пусть даже и хорошему. Особенно когда продукт не обновляется (интернет-то меняется постепенно, новые фичи и всё такое).
P.S. Это не был наезд на Хром, просто объясняю, что конкретно меня тревожит, и почему я заинтересован в дополнительных альтернативах.
поддержка операционной системы Windows XP официально прекращена несколько лет назад
Я знаю об этом. Мне-то что с того, если мне в ней удобно и вообще нравится работать?
Вас не беспокоит, что вы сидите на дырявой, неподдерживаемой, устаревшей операционной системе?
Ничуть не более дырявой, чем все остальные. А насчёт устаревшей — назовите хоть одну причину, почему это так, вот тогда и поговорим. ПРо игры только не надо писать — у меня для этого семёрка рядом стоит. Надо будет — и десятку для игр поставлю, если будет под неё какой-то интересный мне эксклюзив.
И вам не кажется, задуматься о замене ОС вы должны как раз из-за этого?
Нет, я ничего и никому не должен.
Эти альтернативы никогда не стали бы писаться так, чтобы они поддерживали мертвые операционные системы.
Неправда ваша. Погуглите Advanced Chrome, New Moon, K-Meleon (с движком Goanna), Basilisk и Serpent.
И кроме того, я пишу ещё свой браузер параллельно именно из расчёта, чтобы он отлично работал на Windows XP (включая корректный рендеринг текста с субпиксельным сглаживанием).
Просто не люблю быть привязанным к одному единственному продукту, пусть даже и хорошему
Да, подловили, и правда противоречие. Но я писал о программах. ОС — особый разговор :)
Да и программа программе рознь. Взять вот браузер — часто ли вы сталкиваетесь с его интерфейсом, какими-то тонкими возможностями, «потрохами»? Для меня это просто инструмент, позволяющий просматривать веб, то есть некий такой «портал в интернет». Тут привычка не так решает, легче перейти на другой продукт. И то будет заметна разница: изменится высота вьюпорта (это очень сильно замечаешь), цвет UI в верхней области (не везде это можно настроить скинами), скорость прогрузки страниц (как правило, после Хрома — это всегда в меньшую сторону.
Когда я на Хром с Оперы 11 переходил, меня наоборот пару месяцев бесило, что всё грузится «слишком быстро», и я не успеваю насладиться процессом. Да, бывают и такие странности))
Про базовые знания — согласен. Наверное, одной базы маловато будет.
Но я как бы не против изучать что-то новое, если это интересно/полезно. Вы, как мне кажется, мешаете в кучу лень в изучении технологий (что нельзя оправдать) и инструмент для работы (в качестве которого XP ничуть не устарела).
Единственные две области, где она уже не годится — это игры (поскольку нет поддержки нового железа и новых версий DirectX, ну и то что нет 64-битной версии, которую поддерживал бы софт) и аудио-продакшен (новые версии сэмплерных библиотек, хостов и VST не поддерживают XP). Но даже из этих двух второе ограничение — искусственное (созданное производителями софта), принципиальных препятствий работе этих вещей на XP попросту нет.
Да и с играми могло бы обернуться иначе, если бы Microsoft портировала на XP Direct X 10 и 11 (обновив, если нужно, ядро ОС, добавив туда новых фич). Ведь драйвера от моей видеокарты 2012 года под XP вполне себе были выпущены, проблема даже не в железе. И даже будь она в железе — если работа не требовательна к ресурсам (игры здесь идут мимо), всегда можно поставить более старое.
И так почти на каждом третьем сайте. Очень раздражает, да. Если бы не тормоза Firefox — давно бы на него пересел :)
Открыл, посмотрел. не очень понимаю, как читать эти данные. Учёт уязвимостей ведёт (вела) Microsoft, или сообщество? Скорее всего, Microsoft, потому что после 2014-ого года я вижу всего 7-8 штук за все 3 года, тогда как до этого было от 40 до 110 в год. Поддержка же и выпуск патчей как раз была прекращена в 2014-ом.
Вы предлагаете аппроксимировать, и считать число дыр примерно постоянным, независимо от количества фиксов? Если так, то штук 300 должно было накопиться.
С другой стороны, в середине нулевых количество найденных уязвимостей было существенно меньше, и колебалось в районе 20-60 в год. У вас есть этому объяснение?
Кстати, в 2012-ом тоже за год было найдено всего 43.
None Local Low Not required Complete Complete Complete
NDProxy.sys in the kernel in Microsoft Windows XP SP2 and SP3 and Server 2003 SP2 allows local users to gain privileges via a crafted application, as exploited in the wild in November 2013.
2 CVE-2013-5058 189 Overflow +Priv 2013-12-10 2018-10-12 4.9
None Local Low Not required None None Complete
Integer overflow in the kernel-mode drivers in Microsoft Windows XP SP2 and SP3, Windows Server 2003 SP2, Windows Vista SP2, Windows Server 2008 SP2 and R2 SP1, Windows 7 SP1, Windows 8, Windows 8.1, and Windows Server 2012 Gold and R2 allows local users to gain privileges via a crafted application, aka «Win32k Integer Overflow Vulnerability.»
3 CVE-2013-5056 399 DoS Exec Code Mem. Corr. 2013-12-10 2018-10-12 9.3
None Remote Medium Not required Complete Complete Complete
Use-after-free vulnerability in the Scripting Runtime Object Library in Microsoft Windows XP SP2 and SP3, Windows Server 2003 SP2, Windows Vista SP2, Windows Server 2008 SP2 and R2 SP1, Windows 7 SP1, Windows 8, Windows 8.1, Windows Server 2012 Gold and R2, and Windows RT Gold and 8.1 allows remote attackers to execute arbitrary code or cause a denial of service (memory corruption) via a crafted web site that is visited with Internet Explorer, aka «Use-After-Free Vulnerability in Microsoft Scripting Runtime Object Library.»
4 CVE-2013-3940 189 DoS Exec Code Overflow Mem. Corr. 2013-11-12 2018-10-12 9.3
None Remote Medium Not required Complete Complete Complete
Integer overflow in the Graphics Device Interface (GDI) in Microsoft Windows XP SP2 and SP3, Windows Server 2003 SP2, Windows Vista SP2, Windows Server 2008 SP2 and R2 SP1, Windows 7 SP1, Windows 8, Windows 8.1, Windows Server 2012 Gold and R2, and Windows RT Gold and 8.1 allows remote attackers to execute arbitrary code or cause a denial of service (memory corruption) via a crafted image in a Windows Write (.wri) document, which is not properly handled in WordPad, aka «Graphics Device Interface Integer Overflow Vulnerability.»
5 CVE-2013-3918 119 DoS Exec Code Overflow 2013-11-12 2018-10-12 9.3
None Remote Medium Not required Complete Complete Complete
The InformationCardSigninHelper Class ActiveX control in icardie.dll in Microsoft Windows XP SP2 and SP3, Windows Server 2003 SP2, Windows Vista SP2, Windows Server 2008 SP2 and R2 SP1, Windows 7 SP1, Windows 8, Windows 8.1, Windows Server 2012 Gold and R2, and Windows RT Gold and 8.1 allows remote attackers to execute arbitrary code or cause a denial of service (out-of-bounds write) via a crafted web page that is accessed by Internet Explorer, as exploited in the wild in November 2013, aka «InformationCardSigninHelper Vulnerability.»
6 CVE-2013-3900 20 Exec Code 2013-12-10 2018-10-12 7.6
None Remote High Not required Complete Complete Complete
The WinVerifyTrust function in Microsoft Windows XP SP2 and SP3, Windows Server 2003 SP2, Windows Vista SP2, Windows Server 2008 SP2 and R2 SP1, Windows 7 SP1, Windows 8, Windows 8.1, Windows Server 2012 Gold and R2, and Windows RT Gold and 8.1 does not properly validate PE file digests during Authenticode signature verification, which allows remote attackers to execute arbitrary code via a crafted PE file, aka «WinVerifyTrust Signature Validation Vulnerability.»
7 CVE-2013-3899 20 +Priv Mem. Corr. 2013-12-10 2018-10-12 7.2
None Local Low Not required Complete Complete Complete
win32k.sys in the kernel-mode drivers in Microsoft Windows XP SP2 and SP3 and Server 2003 SP2 does not properly validate addresses, which allows local users to gain privileges via a crafted application, aka «Win32k Memory Corruption Vulnerability.»
3 и 5 меня не затрагивают, потому что я никогда не использую Internet Explorer. 4 тоже мимо, потому что я не использую WordPad (ну может что-то открываю в нём раз в год, но это всегда мои собственные файлы, а не полученные со стороны).
Остальное — серьёзнее. Но даже тут скорее всего безопасно, потому что я не запускаю сторонних exe файлов кроме тех, что уже установлены у меня на компьютере. А если что-то ставлю, то смотрю хотя бы подпись и издателя. И в целом ставлю софт очень редко.
Также стоит добавить, что «allows local users to gain proviledges» для меня тоже не актуально, поскольку я — единственный пользователь в системе.
У вас есть пример чего-то такого, что может мне навредить, желательно с примером на пальцах, что я должен для этого сделать, и каковы будут последствия?
Я пока нашёл только две уязвимости, эксплуатируемые через файлы шрифтов, и позволяющие выполнять произвольный код. Это и правда очень плохо, я часто открываю шрифты, в том числе загруженные из интернета с разных каталогов.
Я вам сразу написал, пользуйтесь, только в инет не выходите.
Это почему?) Из-за шрифтов, которые я иногда качаю, и 2-3 уязвимостей в их просмотрщике?
Сравните хотя бы с windows 7:
А чего там сравнивать?.. Почти все уязвимости, которые я просмотрел за 2013-ый год (я мог что-то упустить) — были найдены на всех ОС (включая Win7, 8 8.1). Просто для XP всё что новее января 2014-ого так и не было пофикшено.
Введены новые методы обхода атак ASLR, PatchGuard, UAC, PMIE.
Много пособий по exploit-ам именно для windows xp.
В XP нет UAC в том виде, в котором его привыкли видеть. Или вы о чём сейчас?
OC — тоже программа.
Программа, управляющая всеми другими программами и аппаратными ресурсами. Так-то да, я в курсе, что она программа)
Введены новые методы обхода атак ASLR, PatchGuard, UAC, PMIE
Кстати, из вашей формулировки следует, что и наличие всех этих вещей не сильно спасает, раз «введены методы обхода».
Я удивляюсь почему Вы на windows 9x не сидите
Вы серьёзно или троллите? Попробую предположить, что серьёзно. Окей, потому что 9x падает чаще, и поддерживает меньше оперативной памяти (насколько я помню, 98 SE не увидит даже 4 Гб, хотя возможно я ошибаюсь). Плюс банально требования софта, который я использую. Из всего, что мне нужно, на 98-ой пойдёт разве что Sound Forge 7. Кстати, драйверов на мою звуковую и видеокарту под 98 SE тоже нет.
Были бы драйвера и софт — я бы проверил (на виртуалке я гонял 98 SE довольно много, кстати, всё летало и синих экранов не было). Не сомневаюсь, что скорость её работы была бы ещё выше.
Введены новые методы обхода атак ASLR, PatchGuard, UAC, PMIE.
Много пособий по exploit-ам именно для windows xp.
Возвращаясь к вашей цитате и к статьям, что вы привели по ссылкам: вы таки думаете, что вся вот эта ерунда не потребляект аппаратных ресурсов? Прямо совсем-совсем? Рандомизация адресов требует вычислительных тактов, UAC… Казалось бы, что в ней плохого — но то-то у меня всё стало шевелиться раза в полтора быстрее даже на Windows 7 x64 после её отключения (3.3 GHz @4, 8 Gb RAM). Ну окей, не только её, а ещё 2-3 служб. Prefetcher, кстати, я не отключал — не заметил очень сильного влияния на время запуска ОС, а вот время запуска программ он правда сокращает.
Итак, если допустить, что производительность Windows Vista/7 в режиме работы (не в режиме монопольной работы какого-то приложения типа игры) правда упала, то возникает вопрос — а нафига мне всё это нужно? Поиск уязвимостей и создание патчей к ним и методов защиты — это вечная гонка меча и щита. Я совершенно не собираюсь в ней участвовать в надежде оказаться где-то быстрее хакеров (вместо с вендором ОС), если повезёт.
SP3 Pro, и патчи до лета 2012-ого года стоят включительно.
Linux — может и хорошая система. Но привыкать к полностью новому проводнику, рабочему столу, поменять практически весь софт (кроме браузеров и пары плееров)? Сомнительное предприятие :)
Я кстати в 2009-ом году пробовал играться с Mandriva Linux. Не зашло вроде, утонул в опциях и настройках (в Windows их не то чтобы меньше, но тут я знаю, где что настраивается, а там вот запутался).
Опять же, про софт интересно узнать, много ли приходится работать с консолью (и приходится ли), и так далее.
Просто если человеку вообще не нужна консоль, и он планирует только GUI использовать — чем вообще плоха винда :)
А с консолью у меня тоже тяжко. Пытался подружиться с FreeBSD (для сервера), долго мучился, в итоге забил.
В убунте (и родственных ей дистрибутивах) всё относительно готово для конечного пользователя из коробки — если железо не слишком экзотическое, то зачастую можно просто поставить и пользоваться, про консольку и не вспоминая. В той же мандриве 2009 года у меня категорически не хотел работать GPRS-интернет (а другого у меня тогда и не было), а через год в убунте он завёлся в три клика в настройках сети
Многие другие вещи, которые в 2009-м приходилось делать через консольку, сейчас тоже или совсем автоматизированы, или имеют относительно адекватные гуёвые кнопочки (но точный список таких вещей уже не вспомню). Это, конечно, не только в убунте, но в других дистрибутивах «кнопочек» обычно поменьше и лазать в консольку всё-таки приходится
чем вообще плоха винда :)
Может и ничем
У меня тогда кстати был интернет через ADSL — драйвер от моего модема вряд ли был в составе ОС, а погуглить, как ставить драйвера в мандриве, без интернета я никак не мог (у меня был всего один ноут в те годы, в школе ещё учился).
Но главная беда даже не в этом. Новая ОС — это не только, условно говоря, новый текстовый редактор и другой файл-менеджер. Это другие шрифты, другой механизм рендеринга и сглаживания текста (!), что особенно критично, когда ненативное разрешение монитора юзаешь, новая цветовая гамма. Не всё из этого настраивается так, как привычно, а я очень консервативен в этом плане.
Вот десятку я смог визуально сделать настолько приятной (хоть и не идентичной XP), что готов был ей пользоваться. Однако периодические тормоза, ненужные мне попапы, долгое открытие главного меню из-за плиток, и слишком контрастный дизайн Modern-компонент, включая «панель управления» — всё же вынудили отказаться от её использования…
Кстати, та же «панель управления» в Висте и Семёрке у меня негатива не вызывала в плане своего дизайна (хотя в плане что-то там найти — это мрак, Десятка тут сделала шаг вперёд)…
В отличии от других движков
Не стоит вносить некие «features», которые ещё не одобрены окончательно W3C. Не начинайте очередную войну браузеров. Единственное, чем должен отличаться Ваш движок, уважаемый Автор — это корректной поддержкой всего, что уже есть в стандартах W3C, и скоростью работы (в лучшую сторону относительно других браузеров).
Не всё так просто, следование стандартам W3C будет означать нарушение совместимости со всеми современными браузерами, например https://habr.com/post/353514/
А ещё говорят, что реализовать всё по стандартам эффективно просто невозможно. Настолько невозможно, что гугл переписывает спецификацию под свой хром
Ребята, извините, немного оффтопа. Помогите, пожалуйста, с ответом на вопрос:
https://stackoverflow.com/questions/52568126/cookie-sharing-in-simultaniously-requests
Так уж получилось, что в мире есть всего 4 популярных браузерных движка
А какие ещё два?..
Если это открывающийся тег, он парсит его название тега, атрибуты, а затем, если это параграф и в иерархии тоже есть параграф, удаляет существующий в иерархии тег параграфа и добавляет туда новый, если это не одиночный тег (тег без закрывающегося тега). Если это закрывающийся тег, парсер удаляет из иерархии последний тег и если последний тег был параграфом, то удаляет сразу два последних.
Пожалуйста, вот с этого места поподробнее. Что говорит на этот счёт стандарт?
Это работает только с абзацами? Абзац нельзя вложить в абзац, по логике вещей (такое стандарт должен запрещать). Однако если я напишу такой код:
<div>Какой-то текст
<div>Ещё текст
В таком случае это работать не будет (ведь div можно вложить в div)? Каковы вообще формальные правила автозакрытия тега парсером?
UPD: потестил в Chrome, этот приём работает со ссылками и абзацами внутри div. Если же создать абзац, и попробовать провернуть такое с div-ами — ничего не выйдет, получится пустой абзац, в нём div с текстом и ещё одним div-ом внутри, и после внешнего div-а ещё один пустой абзац.
www.w3.org/TR/html/single-page.html#unclosed-formatting-elements
Вообще, не понятно, какой смысл выделять отдельную категорию тегов, такую как «теги форматирования», если у нас форматированием давно занимается CSS. У нас есть блочные, инлайновые и инлайново-блочные элементы — вот это важно. Блочные не стоит вкладывать в инлайновые — это тоже важно (браузеры кстати обрабатывают эту ситуацию корректно, делая вложенный блочный элемент практически инлайновым по поведению).
А вот эти неконсистентные результаты…
В общем, как бы сделал я на месте разработчиков:
а) В теги
<
b>
, <
i>
и прочие вообще запретил бы вкладывать элементы вроде <
div>
, <
p>
и так далее. Только в обратную сторону — ибо нефиг, должна быть чёткая система правил, что первично, а что вторично.б) Весь неожиданный контент внутри
<
table>
, который не лежит внутри <
td>
— просто вырезать к чертям, как будто его и не было.в) Вот этот последний шестой пример, который я до конца так и не понял, там уж слишком что-то странное — тоже бы запретил так писать. Чистый лист отображать — это конечно перебор, что-то вывести надо, и как-то закрыть незакрытые теги тоже надо. Но алгоритм такого закрытия должен быть проще и предсказуемее в плане результата, имхо.
UPD: Примерно понял, что там происходит. Отдельный список тегов форматирования, который управляется отдельно, и поскольку он не очищен, то создаёт новые
<
b>
элементы даже для пустых абзацев, пока мы его не очистим.Моё мнение не изменилось, я всё ещё считаю, что это полный бред. Теги создавались с целью разметки и структурирования (придания частям текста семантики). Выделять отдельную группу тегов и управлять ей особо — это только создавать сложности верстальщикам и разработчикам браузеров (в случае, если те что-то реализуют не так, тесты не сойдутся с эталоном).
такое ощущение, что просто придумали некий абстрактный алгоритм разбора, потом посмотрели, что он выдаст в этих особых случаях, расписали это, и сказали «да будет так
Примерно так всё и было. Было несколько парсеров в разных браузерах, которые друг под друга подстраивались, потом решили всё это стандартизировать. Это пытались починить посредством xhtml, но верстальщики взбунтовались и теперь имеем то, что имеем: нельзя просто так взять и написать свой браузер не повторив поведение дилетанской поделки двадцатилетней давности.
Обратная совместимость :(
На практике бывают не только незакрытые теги или <b><i></b></i>, но и мутанты типа </br>, я вот видел
(почти всегда)
А иногда ошибка успешно исправляется браузером, и она доживает до продакшена. Поэтому даже я свои сайты периодически прогоняю валидатором, несмотря на то, что давно умею писать валидный код, просто чтобы опечатки выловить
но и мутанты типа
Обычная опечатка, ничего удивительного. С этим случаем всё намного проще: по стандарту тег
<br>
непарный. Можно просто дописать в код парсера одну строчку, которая позволит закрывающий тег рассматривать как открывающий (игнорировать слэш), если тег непарный.Ага, примерно таким и был XHTML, и я даже писал все свои сайты на XHTML, пока его не закопали в угоду HTML5 :(
Вообще в стандартах HTML5 описывается какой-то XML-синтаксис для него, но я что-то не вкурил, как его правильно использовать, да и вживую на сайтах не видел ни разу
Я, к слову, всегда придерживался XHTML синтаксиса (правда последние 3-4 года ленюсь писать значения для атрибутов вроде disabled и т.п.) — но doctype указывал HTML 4.01 Transitional.
Сейчас ведя индивидуальные занятия по HTML/CSS, рекомендую использовать HTML5 doctype, потому что он и пишется короче, и как бы 2018-ый год на дворе обязывает :) Хотя что-то мне подсказывает, что при нормальной правильной разметке вообще разницы почти не будет от того, какой именно указан.
Валидный XHTML не всегда является валидным HTML4 (например, в HTML4 нельзя записать <meta блаблабла />, нужно обязательно <meta блаблабла>)
А для HTML5 я и так пишу в XML-стиле, однако от плохих вестальщиков, пишущих всякие </br> и абсолютно уверенных в правильности этого, это всё равно не спасёт
разницы почти не будет
«Почти». Я пару раз сталкивался с вёрсткой, поехавшей от неправильного доктайпа. Правда, деталей уже не помню, к сожалению
Смотрите, простой эксперимент: если создать на жёстком диске страницу в кодировке windows-1251, и не указать кодировку, то после посещения любого сайта с utf-8 кодировкой в соседней вкладке и последующего обновления нашей локальной страницы у нас будет применяться utf-8 и будут кракозябры (браузер не запускает по какой-то причине процедуру «угадывания» кодировки). Тестил в самой свежей версии Chrome на Win 7.
Теперь попробуем добавить в
<
head>
страницы <meta charset="utf-8"
>
. Проблема уходит. Но стоит добавить слэш: <meta charset="utf-8"
/>
, как проблема возвращается…Что-то у меня не получилось повторить, мой хром безошибочно угадывает кодировку windows-1251 при любых сделанных мной манипуляциях с вкладками. А <meta charset="utf-8"> и <meta charset="utf-8" /> одинаково включают utf-8 и ломают русские буквы как положено
Скажите, а у вас doctype в начале документа проставлен именно HTML5?
Да
Но проблема имела место. Из того, что помню:
Chrome одной из последних версий, возможно, не самой последней, но уже одной из тех, что с новым дизайном, Windows 7 с непонятным набором обновлений. Файл создавали в GridinSoft Notepad 3.3.1 Lite, сохраняет он по умолчанию, надо думать, в ANSI а не в UTF-8.
Баг появлялся именно после просмотра другого сайта, где кодировка UTF-8; если вернуться на вкладку с тестовой страницей, и перезагружать подряд 3, 4 и более раз, проблемы не было.
Я сейчас при тесте использовал даже тот же самый редактор (хотя дома пользуюсь чуть другой версией). Не помогло, не воспроизводится :)
Мне кажется, багнутая версия Хрома была всему виной. Ну или то, что редактор, который мы использовали, имеет какой-то специфичный баг именно под семёркой (редактор очень старый, хотя когда его выпускали, Vista точно уже была в ходу, 2008 год вроде).
Например, сейчас я запустил эту версию (она вроде как portable позиционируется) — проблем нет, правда настройки берутся из моего реестра, от более старой версии, что довольно любопытно. А там была странная вещь: я в окне настроек задавал размер таба в 4 пробела, он вроде куда-то сохранялся, и даже работал, но стоило сохранить файл с расширением .html — как таб становился равным пяти пробелам, и в итоге выравнивание кода превращалось в пытку, приходилось после Tab жать Backspace для выравнивания по предыдущей строке.
Кстати, потом оказалось, что я просто забыл включить принудительную конвертацию табов в пробелы, когда её включил — проблема исчезла. Но сейчас пытаюсь воспроизвести баг на WinXP — никак не выходит, не получается 5 вместо 4, всё чётко — отступ ставится ровно такой, как ставишь в настройках. И даже при отключенной опции «Tabs to spaces» всё нормально.
Так что может, файл сохранялся как-то криво, в других редакторах я его открывать в тот день не пробовал :)
Это я знаю, но это не HTML5 всё-таки (если я правильно интерпретрирую index.xsl, надстройка над старым XHTML?)
Сразу вопрос: а с потребляемой памятью у него как? И идея на далекое будущее (если дело дойдет до релиза): сделать две сборки — одну полноценную с поддержкой всех технологий, вторую — минималистичную, где будет вырезано все ненужное типа WebGL или CSS Animation.
Чтобы можно было использовать вместо Chrome в Electron'e, я так понимаю
А MS Office for Mac — это вообще отдельный проект.
Ну да, не каждой компании под силу такое, верно.
И ещё как минимум на iOS и Android надо
Зачем это? Мы про десктопный софт говорим. И даже не про игры
но долго и дорого
Дороже, но не факт, что очень намного. Во сколько раз зарплата программиста на плюсах выше зарплаты программиста на JavaScript?
Мне скорее кажется, что дело в том, что C++-тулкиты вообще не преднаначены для «той» разработки, которой хотят менеджеры на определённом этапе. «Добавить красненького» или «сделать уголки покруглее» в них достаточно сложно, наоборот — весь UI следует гайдлайнам платформы, а не хотелкам дезигнеров. Зато там просто подключать дополнительные библиотеки и интерироваться с разными сторонними сервисами — а как раз это Electron резко ограничивает, приложение живёт у себя «в песочнице» и оттуда очень сложно выскочить.
Соответственно имеем феномен: с точки зрения менеджеров (они видят и думают исключительно о пикселях, не забыли?) разработка резко ускоряется. С точки зрения пользователей… а тут как бы вилка: часть пользователей видит, что функционал годами не меняется и начинает подумывать о том, что «пора искать альтернативу», часть — считает что VS Code резко лучше какого-нибудь древнего Emacs'а, RHIDE (или вообще Borland C++ 3.1) только потому, что там кнопочки красивее.
Соотношение этих двух групп неизвестно, но судя по успеху VS Code… похоже, что и программисты уже тоже только о пикселях думают.
Если есть альтернатива, то приложение с этим ужасом в пузе я, конечно, никогда не выберу.
А бизнесу продукт «нужен вчера».А получают они его послезавтра. Как у Макаренко — если коротко говорить: сорок сорокарублевых педагогов могут привести к полному разложению не только коллектив беспризорных, но и какой угодно коллектив.
Потому что играться цветами-то легко, а вот выпустить продукт — сложно. То ему памяти не хватает на телефонах с 512MiB (что, вообще-то, больше памяти суперкомпьютеров, на которых атомные бомбы считали), то что-то отваливается на каких-нибудь экзотических GPU (хотя вроде у нас банковский клиент с тремя кнопками, нафига ему GPU), то ещё что-нибудь…
Newtoo — разработка полноценного браузерного движка с нуля в 2018?