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