Promise.bind
Promise.bind(
any|Promise<any> thisArg,
[any|Promise<any> value=undefined]
) -> BoundPromise
Создайте промис, который следует за этим промисом или в статическом методе разрешается заданным value, но привязан к заданному thisArg значению. Связанный промис будет вызывать свои обработчики со связанным значением, установленным в this. Кроме того, промисы, полученные из связанного промиса, также будут связанными промисами с той же thisArg привязкой, что и исходный промис.
Если thisArg является промисом или thenable, его разрешение будет ожидаться, а связанное значение будет значением выполнения промиса. Если thisArg отклоняется, то возвращаемый промис отклоняется с причиной отклонения thisArg's. Обратите внимание, что это означает, что вы не можете использовать this без проверки внутри обработчиков catch для промисов, которые привязаны к промису, потому что в случае отклонения thisArg, this будет undefined.
Без стрелочных функций, предоставляющих лексическую this, соответствие между асинхронным и синхронным кодом нарушается при написании объектно-ориентированного кода. .bind устраняет эту проблему.
Рассмотрим:
MyClass.prototype.method = function() {
try {
var contents = fs.readFileSync(this.file);
var url = urlParse(contents);
var result = this.httpGetSync(url);
var refined = this.refine(result);
return this.writeRefinedSync(refined);
}
catch (e) {
this.error(e.stack);
}
};
Вышеприведенное имеет прямое соответствие:
MyClass.prototype.method = function() {
return fs.readFileAsync(this.file).bind(this)
.then(function(contents) {
var url = urlParse(contents);
return this.httpGetAsync(url);
}).then(function(result) {
var refined = this.refine(result);
return this.writeRefinedAsync(refined);
}).catch(function(e) {
this.error(e.stack);
});
};
.bind — наиболее эффективный способ использования this с промисами. Функции обработчиков в приведенном выше коде не являются замыканиями и, следовательно, могут быть подняты вверх, если это необходимо. Литеральной нагрузки при распространении связанного значения от одного промиса к другому нет.
.bind также имеет полезную побочную цель — обработчики промисов не должны совместно использовать функцию для использования общего состояния:
somethingAsync().bind({})
.spread(function (aValue, bValue) {
this.aValue = aValue;
this.bValue = bValue;
return somethingElseAsync(aValue, bValue);
})
.then(function (cValue) {
return this.aValue + this.bValue + cValue;
});
Вышеприведенное без .bind можно было бы достичь с помощью:
var scope = {};
somethingAsync()
.spread(function (aValue, bValue) {
scope.aValue = aValue;
scope.bValue = bValue;
return somethingElseAsync(aValue, bValue);
})
.then(function (cValue) {
return scope.aValue + scope.bValue + cValue;
});
Однако, при более детальном рассмотрении существуют многочисленные различия:
- Требуется оператор, поэтому его нельзя использовать в контексте выражения
- Если его еще нет, требуется дополнительная функция-обертка для предотвращения утечки или совместного использования
scope - Функции обработчиков теперь являются замыканиями, поэтому менее эффективны и не могут быть повторно использованы
Обратите внимание, что привязка распространяется только при преобразовании промисов. Если вы создаете новые цепочки промисов внутри обработчика, эти цепочки не привязаны к "верхнему" this:
something().bind(var1).then(function() {
//`this` is var1 here
return Promise.all(getStuff()).then(function(results) {
//`this` is undefined here
//refine results here etc
});
}).then(function() {
//`this` is var1 here
});
Однако, если вы используете весь API Bluebird, вам почти никогда не придется прибегать к вложению промисов в первую очередь. Вышеприведенное должно быть написано скорее так:
something().bind(var1).then(function() {
//`this` is var1 here
return getStuff();
}).map(function(result) {
//`this` is var1 here
//refine result here
}).then(function() {
//`this` is var1 here
});
Также обратите внимание на этот ответ на Stackoverflow в качестве дополнительного примера.
Если вы не хотите возвращать связанный промис потребителям промиса, вы можете перепривязать цепочку в конце:
MyClass.prototype.method = function() {
return fs.readFileAsync(this.file).bind(this)
.then(function(contents) {
var url = urlParse(contents);
return this.httpGetAsync(url);
}).then(function(result) {
var refined = this.refine(result);
return this.writeRefinedAsync(refined);
}).catch(function(e) {
this.error(e.stack);
}).bind(); //The `thisArg` is implicitly undefined - I.E. the default promise `this` value
};
Перепривязка также может быть использована для выполнения чего-то излишнего, как это:
Promise.resolve("my-element")
.bind(document)
.then(document.getElementById)
.bind(console)
.then(console.log);
Вышеприведенное выполняет console.log my-element. Такой подход необходим, потому что ни один из методов (getElementById, console.log) не может быть вызван как самостоятельные методы.
© 2013–2018 Petka Antonov
Licensed under the MIT License.
http://bluebirdjs.com/docs/api/promise.bind.html