Promise.map
Promise.map(
Iterable<any>|Promise<Iterable<any>> input,
function(any item, int index, int length) mapper,
[Object {concurrency: int=Infinity} options]
) -> Promise
Для конечной Iterable(массивы являются Iterable), или обещания конечного Iterable, которое возвращает обещания (или смесь обещаний и значений), итерируется по всем значениям в Iterable в массив и преобразует этот массив в другой с помощью заданной mapper функции.
Обещания, возвращаемые функцией mapper , ожидают выполнения, и возвращаемое обещание не выполняется, пока все преобразованные обещания не будут выполнены. Если любое обещание в массиве отклонено, или любое обещание, возвращаемое функцией mapper , отклонено, возвращаемое обещание также отклоняется.
Функция-преобразователь для данного элемента вызывается как можно скорее, то есть, когда обещание для индекса этого элемента в входном массиве выполнено. Это не означает, что элементы в результирующем массиве будут в случайном порядке, это означает, что .map может быть использован для координации конкурентности в отличие от .all.
Распространённое применение Promise.map - замена шаблонного кода .push+Promise.all:
var promises = [];
for (var i = 0; i < fileNames.length; ++i) {
promises.push(fs.readFileAsync(fileNames[i]));
}
Promise.all(promises).then(function() {
console.log("done");
});
// Using Promise.map:
Promise.map(fileNames, function(fileName) {
// Promise.map awaits for returned promises as well.
return fs.readFileAsync(fileName);
}).then(function() {
console.log("done");
});
// Using Promise.map and async/await:
await Promise.map(fileNames, function(fileName) {
// Promise.map awaits for returned promises as well.
return fs.readFileAsync(fileName);
});
console.log("done");
Более сложный пример:
var Promise = require("bluebird");
var join = Promise.join;
var fs = Promise.promisifyAll(require("fs"));
fs.readdirAsync(".").map(function(fileName) {
var stat = fs.statAsync(fileName);
var contents = fs.readFileAsync(fileName).catch(function ignore() {});
return join(stat, contents, function(stat, contents) {
return {
stat: stat,
fileName: fileName,
contents: contents
}
});
// The return value of .map is a promise that is fulfilled with an array of the mapped values
// That means we only get here after all the files have been statted and their contents read
// into memory. If you need to do more operations per file, they should be chained in the map
// callback for concurrency.
}).call("sort", function(a, b) {
return a.fileName.localeCompare(b.fileName);
}).each(function(file) {
var contentLength = file.stat.isDirectory() ? "(directory)" : file.contents.length + " bytes";
console.log(file.fileName + " last modified " + file.stat.mtime + " " + contentLength)
});
Опция Map: concurrency
Вы можете необязательно указать предел конкурентности:
...map(..., {concurrency: 3});
Предел конкурентности относится к обещаниям, возвращаемым функцией-преобразователем, и фактически ограничивает количество созданных обещаний. Например, если concurrency равно 3 , а обратный вызов-преобразователь был вызван достаточно раз, так что в настоящее время ожидаются три возвращаемых обещания, дальнейшие вызовы не происходят, пока одно из ожидающих обещаний не разрешится. Таким образом, функция-преобразователь будет вызвана три раза, и она будет вызвана снова только после того, как по крайней мере одно из обещаний разрешится.
Рассмотрим пример с и без ограничений, и посмотрим, как это влияет на время чтения 20 файлов:
var Promise = require("bluebird");
var join = Promise.join;
var fs = Promise.promisifyAll(require("fs"));
var concurrency = parseFloat(process.argv[2] || "Infinity");
console.time("reading files");
fs.readdirAsync(".").map(function(fileName) {
var stat = fs.statAsync(fileName);
var contents = fs.readFileAsync(fileName).catch(function ignore() {});
return join(stat, contents, function(stat, contents) {
return {
stat: stat,
fileName: fileName,
contents: contents
}
});
// The return value of .map is a promise that is fulfilled with an array of the mapped values
// That means we only get here after all the files have been statted and their contents read
// into memory. If you need to do more operations per file, they should be chained in the map
// callback for concurrency.
}, {concurrency: concurrency}).call("sort", function(a, b) {
return a.fileName.localeCompare(b.fileName);
}).then(function() {
console.timeEnd("reading files");
});
$ sync && echo 3 > /proc/sys/vm/drop_caches $ node test.js 1 reading files 35ms $ sync && echo 3 > /proc/sys/vm/drop_caches $ node test.js Infinity reading files: 9ms
Порядок, в котором map вызывает функцию-преобразователь для элементов массива, не определён, нет гарантий относительно порядка выполнения map для элементов. Для гарантии порядка в последовательном выполнении см. Promise.mapSeries.
© 2013–2018 Petka Antonov
Licensed under the MIT License.
http://bluebirdjs.com/docs/api/promise.map.html