问题
Trying to figure-out how to find something that functional exactly like async.eachSeries, i need a list of async actions run in sequence (not in parallel) but can't find a way to do it in native ES6, can anyone advise, please?
p.s. thought about generators/yield but don't have the experience yet so I'm not realized how exactly it can help me.
Edit 1
per request, here is an example:
Assume this code:
let model1 = new MongooseModel({prop1: "a", prop2: "b"});
let model2 = new MongooseModel({prop1: "c", prop2: "d"});
let arr = [model1 , model2];
Now, I want to run over it in a series, not parallel, so with the "async" NPM it's easy:
async.eachSeries(arr, (model, next)=>{
model.save.then(next).catch(next);
}, err=>{
if(err) return reject(error);
resolve();
})
My question is: with ES6, can I do it natively? without the NPM 'async' package?
Edit 2
With async/await it can be done easily:
let model1 = new MongooseModel({prop1: "a", prop2: "b"});
let model2 = new MongooseModel({prop1: "c", prop2: "d"});
let arr = [model1 , model2];
for(let model of arr){
await model.save();
}
回答1:
For those who like short answers:
[func1, func2].reduce((p, f) => p.then(f), Promise.resolve());
回答2:
Let's say you want to call some async function on an array of data and you want them called sequentially, not in parallel.
The interface for async.eachSeries()
is like this:
eachSeries(arr, iterator, [callback])
Here's how to simulate that with promises:
// define helper function that works kind of like async.eachSeries
function eachSeries(arr, iteratorFn) {
return arr.reduce(function(p, item) {
return p.then(function() {
return iteratorFn(item);
});
}, Promise.resolve());
}
This assumes that iteratorFn
takes the item to process as an argument and that it returns a promise.
Here's a usage example (that assumes you have a promisified fs.readFileAsync()
) and have a function called speak()
that returns a promise when done:
var files = ["hello.dat", "goodbye.dat", "genericgreeting.dat"];
eachSeries(files, function(file) {
return fs.readFileAsync(file).then(function(data) {
return speak(data);
});
});
This lets the promise infrastructure sequence everything for you.
It is also possible for you to sequence things manually (though I'm not sure why):
function eachSeries(arr, iteratorFn) {
return new Promise(resolve, reject) {
var index = 0;
function next() {
if (index < arr.length) {
try {
iteratorFn(arr[index++]).then(next, reject);
} catch(e) {
reject(e);
}
} else {
resolve();
}
}
// kick off first iteration
next();
});
}
Or, a simpler version that manually chains the promises together:
function eachSeries(arr, iteratorFn) {
var index = 0;
function next() {
if (index < arr.length) {
return iteratorFn(arr[index++]).then(next);
}
}
return Promise.resolve().then(next);
}
Note how one of the manual versions has to surround iteratorFn()
with try/catch
in order to make sure it is throw-safe (convert exceptions into a rejection). .then()
is automatically throw safe so the other schemes don't have to manually catch exceptions since .then()
already catches them for you.
回答3:
As an extension to the answer provided by @jib... you can also map an array of items to async functions like so:
[item1, item2]
.map(item => async (prev_result) => await something_async(item))
.reduce((p, f) => p.then(f), Promise.resolve())
.then(() => console.log('all done'));
Notice how prev_result
will be the value returned by the previous evaluation of something_async
, this is roughly equivalent to a hybrid between async.eachSeries
and async.waterfall
.
回答4:
You can chain by returning in the then
callback. For instance:
new Promise(function(resolve, reject){
resolve(1)
}).then(function(v){
console.log(v);
return v + 1;
}).then(function(v){
console.log(v)
});
Will print:
1
2
This of course work when asynchronously resolving promises:
new Promise(function(resolve, reject){
setTimeout(function(){
resolve(1);
}, 1000)
}).then(function(result){
return new Promise(function(resolve, reject){
setTimeout(function(){
console.log(result);
resolve(result + 1);
}, 1000)
});
}).then(function(results){
console.log(results);
});
Printing:
1
2
回答5:
//Uploading this for systems that run lower nodejs version (Azure :/) Not the shortest but the nicest i can think of
for example lets say "functionWithPromise" returns some promise and expects some item.
functionWithPromise(item);
promisesArray =[];
//syncornized
itemsArray.forEach(function (item){
promisesArray.push(functionWithPromise(item));
});
Promise.all(promisesArray).then(function (values){
//profit
});
来源:https://stackoverflow.com/questions/32028552/es6-promises-something-like-async-each