Spec-Zone.ru › Bluebird

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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API