• Чем полезен мономорфизм?
    +2
    Если посмотреть на код, который V8 делает для Typed и Monorphic бенчмарков, то оказывается, что он один и тот же. А производительность почему-то разная. А если переписать код

    // Pregenerate objects
    for (let i = 0; i < n; i++) {
      typed[i] = new Type(i);
    }
    
    for (let i = 0; i < n; i++) {
      poly[i] = {};
      poly[i]["k" + i] = null;
      poly[i].x = i;
    }
    
    for (let i = 0; i < n; i++) {
        mono[i] = {
            x: i,
            n: i, // Add n to balance memory usage
        };
    }
    


    то на моей машине внезапно все выравнивается, что намекает на какие-то мистические источники разницы.
  • Чем полезен мономорфизм?
    +2
    На самом деле ваш мегаморфный совсем отнюдь не мегаморфный, потому что в массиве poly встречаются объекты всего двух разных скрытых классов: с быстрыми элементами и с разреженными.

    // запускать с --allow-natives-syntax для доступа к %HaveSameMap
    let maps = [poly[0]];
    for (let i = 1; i < poly.length; i++) {
      let found = false;
      for (let o of maps) {
        if (%HaveSameMap(o, poly[i])) {
            found = true;
            break;
        }
      }
    
      if (!found) maps.push(poly[i]);
    }
    console.log(maps.length);  // напечает 2
    


    Происходит это потому, что V8 отделяет числовые свойства (т.е. свойствами с именами "0", "1", "2", ...) от других свойств. Сделано это для ускорения работы масивов.

    Вам нужно написать что-нибудь типа poly[i]["k" + i] = null; для создания полноценного мегаморфизма.
  • Что браузеры делают с вашим JavaScript-кодом: об оптимизациях в JS-движках на примере V8
    0
    Если мы хотим оптимизировать

    function f(x) {
      return x.f() // (*)
    }
    
    f(a);
    f(b);
    


    то V8 спотыкается о то, что она при отслеживании метаструктуры рассматривает функции как нечто неделимое, т.е. она будет считать, что вызов в точке (*) полиморфный. А если бы она учитывала, что функция это тело+контекст, то было бы лучше.

    Чинится очень просто: отказом от использования замыканий таким образом на горячих путях.

    function Classic(x) {
      this.x = x;
    }
    
    Classic.prototype.f = function () { return this.x; }
    
    function make(x) {
      return new Classic(x);
    }
    var a = make(0), b = make(1);


    Но это только один пример…

    Можно рассмотреть полиморфизм другого толка:

    function A() { this.x = "a"; this.a = 0; }
    function B() { this.x = "b"; this.b = 0; }
    
    var a = new A(), b = new B();
    
    function use(o) {
      return o.x;
    }
    
    use(a);
    use(b);
    


    Как скомпилировать use(o) во что-то умнее чем (псевдокод):

    function use(o) {
      if (o.hiddenClass === ClassA) {
        return o.x  // load from some fixed offset
      } else if (o.hiddenClass === ClassB) {
        return o.x  // load from some fixed offset
      } else {
        return /* either generic load or deopt */
      }
    }
    


    вопрос открытый
  • Что браузеры делают с вашим JavaScript-кодом: об оптимизациях в JS-движках на примере V8
    0
    Полиморфный код можно, конечно, компилировать, но это отнюдь не так просто, как вам кажется — если хочется добиться, действительно быстрого вызова методов. Это только в С++ у вас есть простые явные vtable-s и все просто, уже в Java начинаются всякие интересности если хочется сделать быструю реализацию интерфейсных вызовов (поищите в интернете статьи о реализации invokeinterface).

    большинство объектных структур будут вполне статисческими


    Это действительно так (хотя и здесь есть свои тонкости). Однако интерес тут представляет не сами объекты, а то, что с ними происходит… Для оптимизации методов, которые работают с этими объектами надо видеть статичность статичность метаструктуры, если можно так выразится. Выше в тексте статьи я приводил уже пример с

    function make(x) {
      return { f: function () { return x } }
    }
    var a = make(0), b = make(1);
    


    здесь не всякая VM может увидеть, что a и b имеют одинаковую метаструктуру — V8, например, не может.
  • Что браузеры делают с вашим JavaScript-кодом: об оптимизациях в JS-движках на примере V8
    0
    Когда я говорю «насколько Facebook/Inbox/etc выигрывает», я как раз и имею ввиду «выигрывает по производительности», т.е. становится быстрее.

    С кодом всяких разных web-приложений все очень не просто — много полиморфизма, сложно оптимизировать, классические оптимизации рассчитанные на мономорфный код часто не окупаются.
  • Что браузеры делают с вашим JavaScript-кодом: об оптимизациях в JS-движках на примере V8
    0
    вопрос о том, насколько Facebook/Inbox/etc выигрывает от того, что его код оптимизировали, решается отнюдь не всегда в пользу оптимизаций :)

    Ну а скоро и WebAssembly подъедет.


    и люди сразу перепишут UI Facebook на С++ вместо JS :)
  • Что браузеры делают с вашим JavaScript-кодом: об оптимизациях в JS-движках на примере V8
    +3
    Он утверждал, что смысл const это просто заменить данный идентификатор значением константы.


    Разумеется в JavaScript семантика у const отнюдь не такая. Самый наглядный пример того, что это все-таки неизменяемая привязка переменной к значению:

    (function () {
      console.log(f()); // prints <?>
      const X = '<!>';
      console.log(f());  // prints <!>
    
      function f() {
        try {
          return X;
        } catch (e) {
          return '<?>'
        }
      }
    })();
    


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

    V8 не использует, к сожалению. А JSC, например, использует. Код

    const X = 10;
    function bar() { return X * X }
    


    компилируется в return 100 по сути дела
  • Что браузеры делают с вашим JavaScript-кодом: об оптимизациях в JS-движках на примере V8
    +1
    В JS скорость парсинга одинаково важна как и скорость исполнения.


    Да скорость парсинга важна. Только ведь скорость парсинга тут вообще сбоку припёка — наличие, отсутствие оптимизирующего компилятора не влияет на нее.

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

    Конечно, не все так просто. Оптимизации могут полагаться на разного рода информацию собранную во время неоптимизированного исполнения — поэтому нужно так реализовывать сбор этой информации, чтобы производительность не страдала. Можете быть уверены — разработчики JS VMs все это стараются учесть и найти баланс между пиковой производительностью и startup.

    Т.е. путь того же Python — простой bytecode interpreter + удобная возможность встраивания native (или тех же bytecodes близких к native) для функций которым нужен CPU на 100%.


    Python — это очень странный пример. Люди ведь совсем даже не поголовно довольны его производительностью — существует целый ряд различных компляторов/реализаций, которые стараются решить проблему производительности. Начиная от Cython и заканчивая PyPy. DropBox вот тоже свой собственный JIT пилит.

    А так… создавать чисто интерпретирумый язык по своей изначальной природе


    Так уж сложилось, что люди которые JavaScript создали, и люди, которые «героически преодолевают его интерпретируемость», это совершенно разные люди.
  • Что браузеры делают с вашим JavaScript-кодом: об оптимизациях в JS-движках на примере V8
    +2
    В таких случая можно баги файлить на GitHub или посылать мне описания непонятных деоптимизаций. Я разьясню деоптимизацию — и куда-нибудь запишу ее как пример для будущих поколений.
  • Что браузеры делают с вашим JavaScript-кодом: об оптимизациях в JS-движках на примере V8
    +1
    В WASM мне не нравится то, что они не поддерживают ничего, что сделало бы этот самый WASM для меня полезным. Меня не интересует возможность запускать C++ браузере. Меня интересует возможность запускать динамические языки в браузере отличные по семантике от JavaScript. Причем я хочу это делать с минимальными издержками. Например, я не хочу компилировать мой написанный на C++ GC в WASM — я хочу полагаться на GC, который уже в браузере есть… при этом, кстати, GC не так-то и просто скомпилировать, потому что я хочу ходить по стеку в поисках корней, а WASM такого не позволяет. Аналогично, я не хочу писать свой JIT — я хочу полагаться на JIT, который в браузере есть — со всеми его мощьными фичами типа адаптивной спекулятивной оптимизации.

    Поэтому от WASM я впервую очередь жду таких фич как интеграция с GC и JIT.
  • Что браузеры делают с вашим JavaScript-кодом: об оптимизациях в JS-движках на примере V8
    +5
    Понятия не имею. Меня про asm.js вообще бесполезно спрашивать, я считаю, что это совершенно бесполезная (или даже вредная) «технология» и мир без нее будет лучше.

    rumkin внизу правильно замечает, что на замену asm.js пришел WASM… Я, впрочем, не большой фанат WASM в его текущей форме.
  • Что браузеры делают с вашим JavaScript-кодом: об оптимизациях в JS-движках на примере V8
    +6
    Я не большой поклонник компиляции C++ в JS. Если WebAssembly получит распространение и поддержку во всех браузерах, то emscripten станет не нужен, потому что для clang есть уже экспериментальный backend, который умеет выдавать WebAssembly.

    Вопрос нужен ли нам WebAssembly я оставлю за рамками — пусть на него отвечают те, кто этим WebAssembly занимаются.
  • Что браузеры делают с вашим JavaScript-кодом: об оптимизациях в JS-движках на примере V8
    0
    Смысл в глубоких оптимизациях JS очень простой — люди пишут JS-код, надо чтобы он исполнялся эффективно.

    Если бы люди JS не писали, то его никто бы и не оптимизировал.

    А так выбора нет :)

  • Что браузеры делают с вашим JavaScript-кодом: об оптимизациях в JS-движках на примере V8
    0
    Для разных машин существуют разные флаги — чтобы посмотреть на сгенерированный код. Тул IRHydra, который я написал, позволяет в более-менее удобоваримом виде изучать информацию, которую умеет дампить V8-овый Crankshaft. Что-то мне подсказывает, что и для других машин есть подобные способы, но разрабочики их не афишируют :)
  • Что браузеры делают с вашим JavaScript-кодом: об оптимизациях в JS-движках на примере V8
    +4
    На русском у меня есть, но мало

    Из более-менее свежего: http://mrale.ph/blog/2015/04/12/jsunderhood.html

    Из старинного есть:

    http://www.youtube.com/watch?v=tCG0aPNvkTs
    http://s3.mrale.ph/TechForum2012.pdf
  • Почему JavaScript работает быстрее, чем С++?
    +4
    Но ведь именно из-за поддержки этих фич, иначе устроен процессинг


    Отнюдь. Различия между re2 и irregexp действительно фундаментальные — но они отнюдь не из-за поддержки этих фич.

    Вот, например, lookbehind в irregexp сделали недавно и никакой особой заморочки с этим не было.

    Для простых регекспов из этого бенчмарка основное преимущество V8 состоит в том, что irregexp транслирует регулярные выражения в машинный код, а не исполняет их на «интерпретаторе», как многие другие regexp движки.

    Ну тут должно быть просто


    На самом деле нет. Вот что на это отвечает Russ Cox (автор re2)

    The lack of generalized assertions, like the lack of backreferences,
    is not a statement on our part about regular expression style. It is
    a consequence of not knowing how to implement them efficiently. If
    you can implement them while preserving the guarantees made by the
    current package regexp, namely that it makes a single scan over the
    input and runs in O(n) time, then I would be happy to review and
    approve that CL. However, I have pondered how to do this for five
    years, off and on, and gotten nowhere.


    https://groups.google.com/d/msg/golang-nuts/7qgSDWPIh_E/OHTAm4wRZL0J

    Иными словами в re2 выбраны и реализованы только те фичи, которые можно эффективно исполнять гарантируя линейную сложность, без катастрофического отката

    А вот что вы имеете в виду под zero-width positive lookahead? Ведь любые lookahead и lookbehind это zero-width match?


    Они так просто часто называются.

    Кстати, lookbehind (?<=re) re2 тоже не поддерживает, если верить документации :)
  • Почему JavaScript работает быстрее, чем С++?
    +3
    lookbehind, atomic groups, possessive quantifiers


    Ни одна из этих фич в regex dna не используется.

    в V8 это встроенная имплементация с довольно урезаным функционалом


    Имплементация V8 — это полноценная имплементация JS RegExp. JavaScriptовые регулярные выражения действительно не поддерживают разные фичи, которые поддерживает re2, но обратное тоже верно — например: JS поддерживает zero-width positive lookahead (?=...) и backreferences \n, а re2 — нет.
  • Тонкости Javascript/Node.js. Увеличиваем производительность в десятки раз
    +4
    Нельзя делать выводы на основе простых измерений, надо хотя бы профилировать и пытаться понять, что же на самом-то деле происходит внутри. Иначе получаются неправильные выводы.

    Дело здесь в следующем — создание функций, которые содержат в себе литералы (например, array literal или там object literal), это более тяжелая операция по сравнению с созданием функций, которые в себе литералов не содержат.

    Если взять и просто сравнить два профиля, то все тайное становится явным

    function find(val){
        function index (value) {
            return [1, 2, 3].indexOf(value);
        }
    
        return index(val);
    }

        8.29%  67  | LazyCompile:*InnerArrayIndexOf native array.js:1020
    *   7.67%  62  | v8::internal::JSFunction::set_literals
    *   7.05%  57  | v8::internal::Factory::NewFunctionFromSharedFunctionInfo
    *   5.81%  47  | v8::internal::Factory::NewFunction
    *   4.58%  37  | v8::internal::Factory::New<v8::internal::JSFunction
    *   4.33%  35  | v8::internal::Runtime_NewClosure
        4.21%  34  | Stub:FastCloneShallowArrayStub
        4.08%  33  | v8::internal::Heap::AllocateRaw
        3.34%  27  | LazyCompile:~index test.js:2
    *   3.34%  27  | v8::internal::Factory::NewFunctionFromSharedFunctionInfo
        3.34%  27  | Builtin:ArgumentsAdaptorTrampoline
        3.09%  25  | v8::internal::Heap::Allocate
    *   3.09%  25  | v8::internal::SharedFunctionInfo::SearchOptimizedCodeMap    
    

    function foo() {
      return [1, 2, 3];
    }
    
    function find(val){
        function index (value) {
            return foo().indexOf(value);
        }
    
        return index(val);
    }

       13.58%  58  | LazyCompile:*InnerArrayIndexOf native array.js:1020
        9.82%  42  | Builtin:ArgumentsAdaptorTrampoline
        7.49%  32  | LazyCompile:~index test1.js:6
        7.01%  30  | LoadIC:A load IC from the snapshot
    *   6.08%  26  | Stub:FastNewClosureStub
        5.62%  24  | Builtin:CallFunction_ReceiverIsNullOrUndefined
        3.74%  16  | LazyCompile:*foo test1.js:1
        3.51%  15  | Builtin:Call_ReceiverIsNullOrUndefined
        3.51%  15  | LazyCompile:*indexOf native array.js:1065        
    

    В первом случае мы ходим много в среду исполнения и там занимаемся всякой тяжелой и малополезной работой (например, клонированием массива литералов привязанного к замыканию), а во втором случае мы быстренько создаем замыкание с помощью FastNewClosureStub. Вот отсюда и основная разница.
  • Dart для всего веба
    0
    Достаточно странный вопрос, я где-то сказал, что «для этого»? Вменяемые библиотеки (включая работу с DOM) — это просто одно из его достоинств, а отнюдь не причина существования.

    В таком ключе и я мог бы спросить: а что для этого нужно полифиллить Array.from и вообще компилировать мой код каким-нибудь babel.js? Оказывается да, нужно таки. Потому что ES6 в настоящий момент тоже язык отдельный от того, что поддерживается браузерами.
  • Dart для всего веба
    +1
    Скорее «почти так», чем «именно так»: Array.from(document.querySelectorAll(".xyz"), el => el.value), потому что NodeList не является Array и как следствие не «умеет» map.
  • Dart для всего веба
    +3
    Часть этих вещей выполняется во время исполнения, компилятор dart2js выкидывает, что может. Если их не исполнять, то другой язык получается.

    Большая часть (частично правдивых) слухов о большом рантайме происходят из тех времен, когда первая версия компилятора просто тупо выплевывала кучу кода, не пытаясь даже удалить все что не используется.

    Голому Hello World особо «рантайма» не нужно, там только прибавляется кусочек который (лениво) инстанцирует классы.

    Основная часть того, что воспринимается как runtime на самом деле в реальных проектах приходит из dart:html. Это библиотека, которая оборачивает DOM и реализует всякие полезные методы, чтобы вы могли писать

    document.querySelectorAll(".xyz").map((el) => el.value) или el.onClick.listen((e) { /* ... */ })

    вместо голого JSовго [].slice.call(document.querySelectorAll(".xyz")).map(function (el) { return el.value }) и el.addEventListener("click", function () {}), т.е. в некотором смысле dart:html это такая специально заточеная для Dart jQuery.

    Компилятор старается выкинуть все что можно, но он же не знает, что там querySelector вернет — поэтому остается всякий потенциально неиспользуемый код. Сравнивать этот «рантайм» нужно, конечно же, не с голым JS, а с размером всех тех либ которые вы будете использовать в своем коде (jQuery там или lodash).
  • Dart для всего веба
    0
    В виде плагина его не добавишь, потому что PPAPI не дает сделать легковесную тесную интеграцию с DOM.
  • Dart для всего веба
    +9
    Если вы посмотрите на Dart, то обнаружите, что он не только добавляет, но и убирает.

    Семантически Dart достаточно отличается от JavaScript объектной моделью. Вместо концепции «любой объект это словарь с прототипом», в Dart обычные классы с фиксированной структурой. В JavaScript вы читаете свойство, которого нет, и получаете undefined, в Dart вы получаете исключение. В JS вы складываете null + 1 получаете 1 (или undefined + 1 получаете NaN), в Dart вы получаете опять же исключение (и нет никакого undefined). Иными словами то «что не хватает в TS, а есть в dart также» — это в некотром смысле отрицательная величина, потому что Dart упрощает семантику и убирает те части JS, которые скажем так мешают вам поймать ошибку в коде как можно раньше.

    Конечно же, Dart не только убирает, но и довавляет. Например, в Dart можно переопределить операторы + или допустим [], или каждый класс может иметь метод noSuchMethod, который позволяет динамически регировать на вызов несуществующих методов и менять поведение объекта (можно, например, легко написать proxy объект на основе этого метода).

    Плюс Dart это не только язык, это еще и платформа с библиотеками спроектированными так, чтобы хорошо работать с его семантикой. В TypeScript библиотек вообще нет, люди просто .d.ts декларациями к тому, что есть в JavaScript.
  • Dart для всего веба
    +1
    Никак не связанна. Oilpan вообще особо никак не связан был с Dart (хотя и существовали некоторые теоретические предположения о том, что он может облегчить интеграцию Dart и Blink в вопросах GC).

    Dart не будут интегрировать в стандартной сборке, но другие варианты какие-нибудь останутся (за исключением Dartium)?


    Не совсем понятен вопрос. Существует всего один Chrome, поэтому не ясно о каких вариантах идет речь.

    Dartium останется, потому что пока это единственный способ гарантировать быстрый edit-refresh цикл разработки.
  • Очень быстрые классы на JavaScript с красивым синтаксисом
    +1
    Конкретное значение уже зависит от CPU и т.д.

    Вот после некоторых мучений нарисовал тест демонстрирующий проблему с полиморфизмом на FF

    jsperf.com/liquidlava-class-system-performance-ff

    FF не микробенчмарке действительно очень умело избегает этой полиморфной ловушки, но это срабатывает только если бенчмарк постоянно крутится с одним и тем же объектом.

  • Очень быстрые классы на JavaScript с красивым синтаксисом
    +1
    Это решает проблему с «отложенной» инициализацией полей и, как следствие, убирает проблему нестабильной формы объекта, копирование функций решает другую проблему — если у вас есть разные классы наследники, то функция сидящая на прототипе базового класса будет видеть их всех — и как следствие будет полиморфной, даже если каждый отдельный класс наследник будет производить объекты стабильной формы. Если каждый класс наследник пользуется своей копией «базовой» функции — то каждая такая копия мономорфна.
  • Очень быстрые классы на JavaScript с красивым синтаксисом
    +1
    Если взять открыть в чистой вкладке в Хроме и выполнить сначала «Lava method call», а потом «Lava method call (2)», то должна нарисоваться такая картина. Если их выполнить в каком-то другом порядке или допусти выполнить «Lava method call» еще раз после того как «Lava method call (2)» открутится, то «Lava method call» будет такой же медленный как и «Lava method call (2)», потому что type feedback стал полиморфный.

    С FF картина интересная, все что я говорю — оно только к V8 относится. Скорее всего в этом микробенчмарке, он (совершенно правильно) понимает что полиморфизма тут быть не может. Ох, если бы только было легко посмотреть в их сгенерированный код, без пересборки jsshell из исходников.
  • Очень быстрые классы на JavaScript с красивым синтаксисом
    +1
    Он влияет только если создать больше одного объекта и у обоих дернуть метод пару раз — иначе незаметно (связанно это с тем, что inline caches проходят через PREMONOMOPRHIC state и это скрывает полиморфизм, второй объект выявляет это — потому что PREMONOMOPRHIC уже пройден и мы находимся в MONOMORPHIC). Посмотрите на Lava method call (2) в моей версии.
  • Очень быстрые классы на JavaScript с красивым синтаксисом
    +1
    Посмотрел сообщения от RubaXa, вспомнил специфику. Там сравнивалось Base.prototype.method.call(this) и __.parent.call(this), где __ указывал на method в потомке, а __.parent на метод в базовом классе, т.е. Base.prototype.method. Причем все это было год назад, до того как V8 научился распознавать f.call. Из-за этого .call не проинлайнивался, и как следствие LICM не выносил LoadFunctionPrototype из цикла. Как следствие каждая лишняя инструкция была на счету и отражалась на результате микробенчмарка. (Плюс еще во втором случае на одно разыменование меньше, все складывается)
  • Очень быстрые классы на JavaScript с красивым синтаксисом
    +6
    В вашем бенчмарке была своя специфика (я правда уже не помню какая :)). В данном конкретном случае специфика немножко другая.

    Если вам кажется, что тут я считерил — то напишите свои тесты, быстрее все равно не будет.


    Легким движением руки

    - NativeParentClass.prototype.method.apply(this);
    + NativeParentClass.prototype.method.call(this);
    


    NativeInstance.method разгоняется на Хроме в 20 раз см jsperf.com/liquidlava-class-system-performance/9

    А все почему? Потому что f.apply(this) Crankshaft не распознает. Он всегда умел f.apply(this, arguments) распознавать и недавно его научили f.call(...). Если вызов метода родителя распознается — то все проинлайнивается и различные инварианты типа LoadFunctionPrototype выносятся LICMом за пределы самого горячего цикла и, как следствие, на результат бенчмарка влияют мало (см IR цикла, красная полоса — индикатор вложенности циклов).

    Кстати, LoadFunctionPrototype похудел, он все еще больше чем одинокий mov, но меньше, чем то чудовище, которое раньше генерировалось.

    Хочется еще отметить, что замеряемый код содержит в себе один печальный антипаттерн — начальное значение this.counter экземплярам потомков приходит из прототипа, из-за этого если создать два экземпляра и дергать у них по-очереди method, то в этом самом методе возникает нездоровый полиморфизм, который может скушать на этом микробенчмарке до 50% производительности.

    В целом, наследование в JS, особенно когда у базового «класса» много детей и часть методов ими всеми разделяется, в настоящее время это performance antipattern, потому что все разделяемые методы становятся мучительно полиморфными внутри. Поэтому в коде для которго действительно важна каждая инструкция наследования стоит избегать или насильно клонировать все методы с прототипа базового класса в прототип дочернего — причем не копировать по ссылке, а именно клонировать, например, с помощью компиляции клонов через Function-конструктор.
  • Пишем быстрый и экономный код на JavaScript
    +1
    Разумеется если массив у нас изначально состоит из чисел (для других случаев тип элементов не отслеживается), то null действительно переведёт его просто в массив «чего угодно»), в этом случае a[i] = null не подходит. Надо либо сдвигать элементы, либо писать специальный маркер в несуществующие позиции (например, a[i] = 0). Конкретный подход зависит от назначения конкретного массива и причин, по которым нужно из него удалять элементы.
  • Пишем быстрый и экономный код на JavaScript
    +1
    Это хак связанный с тем, что V8 старается держать прототипы объектов в fast mode. Получается, когда вы присваиваете медленный объект (dictionary/slow mode) в f.prototype он превращается в быстрый.

    Сей хак актуален, если вы знаете, что у вас есть объект находящийся по какой-то причине в словарном режиме и вам хочется его превратить в быстрый объект.
  • Пишем быстрый и экономный код на JavaScript
    0
    Лимит про 100000 для new Array(n) стал для V8 неактуальным после codereview.chromium.org/397593008, теперь преаллокация быстрее, потому что преалоцированный массив остается быстрым. До этой правки он превращался в словарь.
  • Все способы перебора массива в JavaScript
    +1
    Я не сказал, что он будет работать быстрее. Я скорее сказал: это иллюзия, что он будет работать медленнее «потому что length в цикле больше никто не читает» — как CPU положит, так и будет работать :) У меня есть машина (с Xeonом) там у меня получилось быстрее — я это исключительно для того в пост добавил, чтобы показать, что это все замеры погоды в северном полушарии.
  • Пишем быстрый и экономный код на JavaScript
    0
    Рекомендации про удаление относится к использованию оператора delete.

    Если у вас есть объект, который вы используете как словарь (а не как объект), то кроме удаления deleteом ничего не сделаешь.

    Если же у вас именно объект — то лучше просто сделать o.p = null.

    С массивом точно также — если массив уже разреженный с кучей дырок, т.е. словарь по сути дела — то пользуйтесь delete, в противном случае либо a[i] = null или двигайте элементы вниз (тем же splice или руками)

    Все эти рекомендации не следует применять в слепую — надо просто понимать потенциальные проблемы, профилировать и решать уже после профилировки как разбираться с hotspotами.
  • Пишем быстрый и экономный код на JavaScript
    0
    это jsperf.com'овые графики, он все выражает в операциях в секунду.
  • Harmony collections NOW
    +1
    Если не будет утекать в этих кейсах, будет утекать в других. Невозможно реализовать правильную семантику WeakMap в виде shim — из сильных ссылок, слабые не соорудить.
  • Harmony collections NOW
    +1
    Заметьте я говорю про shim описанный в статье. При нативной реализации WeakMap в JS VM, конечно же, ничего ни в первом, ни во втором случае не должно утечь (если утекает — то это баг в реализации :)).

    А в shim описанном в статье утечет, потому что мы при выполнении m.set(x, y) мы по сути дела прикрепляем y сильным образом к x, там к x прикрепляется специальная структурка. По сути дела у нас произошла перестановка из Map * Key → Value мы делаем Key * Map → Value и храним значения на ключах, индексируя их мапами. Такой shim не течет в том смысле, что если ключ «помер», то мап не будет без дела удерживать значения, но до настоящей семантики он не дотягивает. Потому что если ключ не помер, то нем эта вспомогательная структурка будет вечно висеть и содержать (и удерживать) мертвые куски относящиеся к умершим мапам.
  • 10 самых распространённых ошибок при программировании на JavaScript
    0
    7. Неправильное наследование через прототипы


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