Spec-Zone.ru › Bluebird

Promise.promisifyAll

Promise.promisifyAll(
    Object target,
    [Object {
        suffix: String="Async",
        multiArgs: boolean=false,
        filter: boolean function(String name, function func, Object target, boolean passesDefaultFilter),
        promisifier: function(function originalFunction, function defaultPromisifier)
    } options]
) -> Object

Обещает весь объект, перебирая свойства объекта и создавая асинхронный эквивалент каждой функции в объекте и его цепочке прототипов. Имя обещаемой функции будет исходным именем функции с суффиксом suffix (по умолчанию "Async"). Также обещаются свойства класса объекта (что характерно для основного экспорта многих модулей), как статические, так и методы экземпляров. Свойство класса — это свойство с функциональным значением, имеющее непустой .prototype объект. Возвращает входной объект.

Обратите внимание, что исходные методы в объекте не перезаписываются, а создаются новые методы с суффиксом Async. Например, если вы promisifyAll объект node.js fs, используйте fs.statAsync для вызова обещаемого stat метода.

Пример:

Promise.promisifyAll(require("redis"));

//Later on, all redis client instances have promise returning functions:

redisClient.hexistsAsync("myhash", "field").then(function(v) {

}).catch(function(e) {

});

Это также работает с синглетонами или конкретными экземплярами:

var fs = Promise.promisifyAll(require("fs"));

fs.readFileAsync("myfile.js", "utf8").then(function(contents) {
    console.log(contents);
}).catch(function(e) {
    console.error(e.stack);
});

См. обещание для получения дополнительных примеров.

Вся цепочка прототипов объекта обещается для объекта. Рассматриваются только перечисляемые свойства. Если у объекта уже есть обещанный вариант метода, он будет пропущен. Предполагается, что целевые методы соответствуют соглашению node.js с обратными вызовами, принимая обратный вызов в качестве последнего аргумента и вызывая этот обратный вызов с ошибкой в качестве первого аргумента и успешным значением во втором аргументе. Если узел вызывает свой обратный вызов с несколькими успешными значениями, значение выполнения будет массивом этих значений.

Если у имени метода уже есть суффикс "Async", будет выброшено исключение.

Опция: суффикс

По желанию вы можете определить пользовательский суффикс через объект опций:

var fs = Promise.promisifyAll(require("fs"), {suffix: "MySuffix"});
fs.readFileMySuffix(...).then(...);

Все вышеперечисленные ограничения применимы к настраиваемым суффиксам:

  • Тщательно выбирайте суффикс, он не должен конфликтовать ни с чем
  • Используйте суффикс в формате PascalCase
  • Суффикс должен быть допустимым идентификатором JavaScript, использующим буквы ASCII
  • Всегда используйте один и тот же суффикс во всем приложении, вы можете создать обертку, чтобы это было проще:
module.exports = function myPromisifyAll(target) {
    return Promise.promisifyAll(target, {suffix: "MySuffix"});
};

Опция: multiArgs

Установка multiArgs на true означает, что полученное обещание всегда будет выполнено с массивом успешного(ых) значения(ий) обратного вызова. Это необходимо, потому что обещания поддерживают только одно успешное значение, в то время как некоторые API обратных вызовов имеют несколько успешных значений. По умолчанию игнорируются все, кроме первого, успешного значения функции обратного вызова.

Если в модуле обратные вызовы с несколькими аргументами являются исключением, а не правилом, вы можете отфильтровать методы с несколькими аргументами на первом шаге, а затем обещать остальной модуль на втором шаге:

Promise.promisifyAll(something, {
    filter: function(name) {
        return name === "theMultiArgMethodIwant";
    },
    multiArgs: true
});
// Rest of the methods
Promise.promisifyAll(something);

Опция: фильтр

По желанию вы можете определить пользовательский фильтр через объект опций:

Promise.promisifyAll(..., {
    filter: function(name, func, target, passesDefaultFilter) {
        // name = the property name to be promisified without suffix
        // func = the function
        // target = the target object where the promisified func will be put with name + suffix
        // passesDefaultFilter = whether the default filter would be passed
        // return boolean (return value is coerced, so not returning anything is same as returning false)

        return passesDefaultFilter && ...
    }
})

Функция фильтрации по умолчанию проигнорирует свойства, начинающиеся с ведущей подчёркивания, свойства, которые не являются допустимыми идентификаторами JavaScript, и конструкторы функций (функции, имеющие перечисляемые свойства в их .prototype).

Опция: promisifier

По желанию вы можете определить настраиваемый promisifier, чтобы, например, обещать API chrome, используемые в расширениях Chrome.

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

function DOMPromisifier(originalMethod) {
    // return a function
    return function promisified() {
        var args = [].slice.call(arguments);
        // Needed so that the original method can be called with the correct receiver
        var self = this;
        // which returns a promise
        return new Promise(function(resolve, reject) {
            args.push(resolve, reject);
            originalMethod.apply(self, args);
        });
    };
}

// Promisify e.g. chrome.browserAction
Promise.promisifyAll(chrome.browserAction, {promisifier: DOMPromisifier});

// Later
chrome.browserAction.getTitleAsync({tabId: 1})
    .then(function(result) {

    });

Сочетание filter с promisifier для модуля restler для обещанного генератора событий:

var Promise = require("bluebird");
var restler = require("restler");
var methodNamesToPromisify = "get post put del head patch json postJson putJson".split(" ");

function EventEmitterPromisifier(originalMethod) {
    // return a function
    return function promisified() {
        var args = [].slice.call(arguments);
        // Needed so that the original method can be called with the correct receiver
        var self = this;
        // which returns a promise
        return new Promise(function(resolve, reject) {
            // We call the originalMethod here because if it throws,
            // it will reject the returned promise with the thrown error
            var emitter = originalMethod.apply(self, args);

            emitter
                .on("success", function(data, response) {
                    resolve([data, response]);
                })
                .on("fail", function(data, response) {
                    // Erroneous response like 400
                    resolve([data, response]);
                })
                .on("error", function(err) {
                    reject(err);
                })
                .on("abort", function() {
                    reject(new Promise.CancellationError());
                })
                .on("timeout", function() {
                    reject(new Promise.TimeoutError());
                });
        });
    };
};

Promise.promisifyAll(restler, {
    filter: function(name) {
        return methodNamesToPromisify.indexOf(name) > -1;
    },
    promisifier: EventEmitterPromisifier
});

// ...

// Later in some other file

var restler = require("restler");
restler.getAsync("http://...", ...,).spread(function(data, response) {

})

Использование параметра defaultPromisifier для добавления улучшений поверх обычной обещанной ноды:

var fs = Promise.promisifyAll(require("fs"), {
    promisifier: function(originalFunction, defaultPromisifer) {
        var promisified = defaultPromisifier(originalFunction);

        return function() {
            // Enhance normal promisification by supporting promises as
            // arguments

            var args = [].slice.call(arguments);
            var self = this;
            return Promise.all(args).then(function(awaitedArgs) {
                return promisified.apply(self, awaitedArgs);
            });
        };
    }
});

// All promisified fs functions now await their arguments if they are promises
var version = fs.readFileAsync("package.json", "utf8").then(JSON.parse).get("version");
fs.writeFileAsync("the-version.txt", version, "utf8");

Обещание нескольких классов за один раз

Вы можете обещать несколько классов за один раз, создав массив из классов и передав его в promisifyAll:

var Pool = require("mysql/lib/Pool");
var Connection = require("mysql/lib/Connection");
Promise.promisifyAll([Pool, Connection]);

Это работает, потому что массив действует как «модуль», где индексы являются свойствами «модуля» для классов.

© 2013–2018 Petka Antonov
Licensed under the MIT License.
http://bluebirdjs.com/docs/api/promise.promisifyall.html

Spec-Zone.ru

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