Подтвердить что ты не робот

Будет ли функция Function.prototype.bind() всегда медленной?

Я пишу библиотеку с открытым исходным кодом javascript, и я сильно использую метод .bind(), потому что у меня есть идея, что объектно-ориентированный код выглядит более понятным тогда. (спорный, хотя)

Пример

A1:

var that = this;

setTimeout(function () {
    that.method();
}, 0);

против

B1

setTimeout(this.method.bind(this), 0);

Или более практичная часть кода

A2:

remoteDataSource.getData(function (a, b, c, d) {
     obj.dataGetter(a, b, c, d);
})

vs B2:

remoteDataSource.getData(obj/* or prototype */.dataGetter.bind(obj));

Я использую non-native bind для старых браузеров, и все прошло идеально, пока я не открыл тест jsperf для привязки.

Похоже, что код с использованием bind в 100 раз медленнее. Теперь, прежде чем переписывать всю мою библиотеку, у меня есть вопрос для тех, кто знаком с движками javascript:

Есть ли вероятность того, что, будучи новой функцией, bind будет оптимизирована  скоро, или нет шансов из-за ограничений архитектуры JavaScript?

4b9b3361

Ответ 1

Прежде всего, зафиксирован jsperf http://jsperf.com/bind-vs-emulate/13.

= Вы не должны воссоздавать статические функции внутри эталона. Это нереально, потому что в реальном коде статические функции создаются только один раз.

Вы можете видеть, что шаблон var self = this все еще на 60% быстрее. Но для этого требуется определение функции, где вы можете связываться из любой точки и, следовательно, иметь лучшую ремонтопригодность.


Ну нет, встроенная семантика связывания смехотворно запутана.

Когда я связываюсь, я просто хочу:

function bind(fn, ctx) {
    return function bound() {
        return fn.apply(ctx, arguments);
    };
}

Если бы я хотел предварительно применить аргументы или использовать черную магию глубокого конструктора, мне бы хотелось, чтобы для этого была совершенно другая функция. Я понятия не имею, почему это было включено в bind.

<rant> Btw, та же проблема связана с почти чем-либо, введенным в ES5, наказывая общий случай, заставляя реализации обрабатывать некоторый теоретический краевой случай, который вряд ли имеет отношение к кому-либо на практике. Следующая языковая версия продолжается по тому же пути. </rant>

Эмулированное связывание даже не пытается эмулировать привязку вообще. И даже если вы попытаетесь подражать ему, вы не сможете сделать это полностью, чтобы просто нечестно.

Таким образом, при всем остальном, равном *, встроенное связывание не может быть быстрее, чем обычное связывание, которое просто связывается.

* В JITs код пользователя не имеет существенного недостатка для встроенного кода. Фактически оба SM и V8 реализуют множество встроенных модулей в Javascript.

Ответ 2

В настоящее время, в конце 2013 года, наилучшим решением будет реализация рукопашных версий Function.prototype.bind и либо переопределить собственный "поставщик" (не являющийся по-настоящему родным), либо собственный код javascript, либо используйте свой собственный myBind.

Function.prototype.apply выполняется довольно быстро, а нарезка, согласование и сдвиг массива выполняется медленно, поэтому лучше использовать apply вместо bind или минимизировать манипуляции с аргументами в функции myBind. Это оставит вас без возможности предварительной настройки параметров.

Поэтому я не вижу необходимости переписывать все обратно на закрытие (уродливый var that = this;). Пусть функциональный характер javascript победит.

Более подробные и рабочие примеры кода здесь:

http://jsperf.com/function-bind-performance/4

http://jsperf.com/function-bind-performance/5

http://jsperf.com/bind-vs-emulate/4.. 10.

Подведение итогов: обходные решения не так уж плохи. Используйте их храбро. Если вы используете не полностью признанный bind, не заходите слишком далеко от оригинальной концепции, так как я не нашел причин, которые он еще не реализовал в C. Это вопрос времени.