Skip to content

Instantly share code, notes, and snippets.

@Busyrev
Last active September 28, 2017 15:15
Show Gist options
  • Save Busyrev/9c832c43f5ab216a44e7aaff2c98a98e to your computer and use it in GitHub Desktop.
Save Busyrev/9c832c43f5ab216a44e7aaff2c98a98e to your computer and use it in GitHub Desktop.
Рассуждения о (0, this.callback)();

По мотивам диалога в телеграмме:

@artur_viktorovich:

А как вы в TS пишете выражения вида (0, this.function)()?

На вопрос зачем такое писать, было сказано следующее:

более быстрый (где-то я такое слышал) аналог this.function.call(void 0)

Ну проверим

Для начала, от того, указываем "use strict" или нет будет зависеть то, как это всё будет работать. Внутри коллбека будет либо window либо undefined (если мы туда конечно что-то другое не передадим). Код можно посмотреть в CallbackPerfTests.ts, запустить у вас его не получится, ибо я это делал в своём тестовом фреймворке, переписать это на чистый js без завязки на пандовский тестэнджин предлагается читателю для самостоятельнйо работы.

Вот какие способы написать желаемое я использовал

test_callSeparateMulti
    let exCb = this.callback;
    exCb();
    
test_callCallVoid0Multi
    this.callback.call(void 0);
    
test_callApplyVoid0Milti
    this.callback.apply(void 0);
	
test_callWith0Multi
    (0, this.callback)();
    
test_callCallUndefinedMulti
    this.callback.call(undefined);
    
test_callApplyUndefinedMulti
    this.callback.apply(undefined);

test_callCallNullMulti
    this.callback.call(null);

test_callApplyNUllMulti      
    this.callback.apply(null);

Результаты тестов

Хром 60 1e9 итераций

test name ms
test_callSeparateMulti 1198
test_callCallVoid0Multi 1200
test_callApplyVoid0Milti 1193
test_callWith0Multi 1201
test_callCallUndefinedMulti 1191
test_callApplyUndefinedMulti 1200
test_callCallNullMulti 1193
test_callApplyNUllMulti 1199

55 файерфокс, 1e7 итераций (в 100 раз меньше хрома)

test name ms
test_callSeparateMulti 8
test_callCallVoid0Multi 8
test_callApplyVoid0Milti 2675
test_callWith0Multi 7
test_callCallUndefinedMulti 8
test_callApplyUndefinedMulti 2663
test_callCallNullMulti 9
test_callApplyNUllMulti 2664

ie 11 1e7 итераций

test name ms
test_callSeparateMulti 55
test_callCallVoid0Multi 82
test_callApplyVoid0Milti 306
test_callWith0Multi 67
test_callCallUndefinedMulti 81
test_callApplyUndefinedMulti 306
test_callCallNullMulti 87
test_callApplyNUllMulti 302

Edge 15 1e7 итераций

test name ms
test_callSeparateMulti 13
test_callCallVoid0Multi 13
test_callApplyVoid0Milti 406
test_callWith0Multi 7
test_callCallUndefinedMulti 15
test_callApplyUndefinedMulti 424
test_callCallNullMulti 14
test_callApplyNUllMulti 401

Итого

test_callWith0Multi, а именно (0, this.callback)(); оказался незначительно быстрее только в Edge. В поведении не отличается от классических способов избавиться от контекста, таким образом никакого смысла данная конструкция не имеет и к применению противопоказана.

Также видно что apply без аргумента работает медленней чем call везде, кроме chrome, причём местами достаточно сильно медленнее.

Вместо распространения странных слухов о скорости разных синтаксических конструкций пишите тесты на производительность, это не так сложно, но даёт достоверный результат, но делайте это правильно.

Смотрите годные доклады

Вячеслав Егоров — Производительность JavaScript через подзорную трубу

https://www.youtube.com/watch?v=HPFARivHJRY

Почему бенчмаркать нужно с умом

https://www.youtube.com/watch?v=tS6XHqRhpEQ&feature=youtu.be&t=1h56m34s Слайды к докладу https://docs.google.com/presentation/d/1Nii3bxeSvLtFeLtpXi_G9Ue_LVl28_WjGKJs4O1QoOA/edit

///ts:ref=TestRunner
/// <reference path="../../../panda/testEngine/TestRunner.ts"/> ///ts:ref:generated
class CallbackPerfTests extends TestRunner {
public callback:Function = function() {
return this;
};
public numIterations = 1E7;
public test_call(a:Assert):void {
a.equals(this.callback(), this, 'this inside callback is this');
a.testDone();
}
public test_callSeparate(a:Assert):void {
let exCb = this.callback;
a.equals(exCb(), undefined, 'this inside callback is undefined');
a.testDone();
}
public test_callCallVoid0(a:Assert):void {
a.equals(this.callback.call(void 0), undefined, 'this inside callback is undefined');
a.testDone();
}
public test_callApplyVoid0(a:Assert):void {
a.equals(this.callback.apply(void 0), undefined, 'this inside callback is undefined');
a.testDone();
}
public test_callWith0(a:Assert):void {
a.equals((0, this.callback)(), undefined, 'this inside callback is undefined');
a.testDone();
}
public test_callCallUndefined(a:Assert):void {
a.equals(this.callback.call(undefined), undefined, 'this inside callback is undefined');
a.testDone();
}
public test_callApplyUndefined(a:Assert):void {
a.equals(this.callback.apply(undefined), undefined, 'this inside callback is undefined');
a.testDone();
}
public test_callCallNull(a:Assert):void {
a.equals(this.callback.call(null), null, 'this inside callback is null');
a.testDone();
}
public test_callApplyNUll(a:Assert):void {
a.equals(this.callback.apply(null), null, 'this inside callback is null');
a.testDone();
}
public test_callSeparateMulti(a:Assert):void {
let exCb = this.callback;
let l = this.numIterations;
for (let i=0; i < l; i++) {
exCb();
}
a.testDone();
}
public test_callCallVoid0Multi(a:Assert):void {
let l = this.numIterations;
for (let i=0; i < l; i++) {
this.callback.call(void 0);
}
a.testDone();
}
public test_callApplyVoid0Milti(a:Assert):void {
let l = this.numIterations;
for (let i=0; i < l; i++) {
this.callback.apply(void 0);
}
a.testDone();
}
public test_callWith0Multi(a:Assert):void {
let l = this.numIterations;
for (let i=0; i < l; i++) {
(0, this.callback)();
}
a.testDone();
}
public test_callCallUndefinedMulti(a:Assert):void {
let l = this.numIterations;
for (let i=0; i < l; i++) {
this.callback.call(undefined);
}
a.testDone();
}
public test_callApplyUndefinedMulti(a:Assert):void {
let l = this.numIterations;
for (let i=0; i < l; i++) {
this.callback.apply(undefined);
}
a.testDone();
}
public test_callCallNullMulti(a:Assert):void {
let l = this.numIterations;
for (let i=0; i < l; i++) {
this.callback.call(null);
}
a.testDone();
}
public test_callApplyNUllMulti(a:Assert):void {
let l = this.numIterations;
for (let i=0; i < l; i++) {
this.callback.apply(null);
}
a.testDone();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment