Reputation: 700
I have an array of promises I try to process one after the others
function asyncInsertMagFromFile(file, resolve) {
//some asynchronous processing with file
resolve();
}
let magRequests = fs.readdirSync(storeDir).map(function(file) {
return new Promise(resolve => {
asyncInsertMagFromFile(file, resolve);
});
});
I'm trying to process these promises (magRequests) "synchronously" without success. Lot's of questions about that subject exist but I havent found one that fit with my problem. I tried some of trincot solutions here https://stackoverflow.com/a/40329190/7531001 but I don't know how to handle my file parameter.
For example this doesn't work (await is only valid in async function)
(async function loop() {
fs.readdirSync(storeDir).forEach(function(file) {
await new Promise(resolve =>
asyncInsertMagFromFile(file, resolve)
);
});
})();
Any idea how I can fix this ?
Upvotes: 0
Views: 78
Reputation: 39310
If you want to process in series and process the result then you could use recursion:
const FAILED = {};
const processImages = (files) => {
const recur=(files,result) => {
if(files.length===0){
return result;
}
return asyncInsertMagFromFile(files[0])
.catch(error=>FAILED)//always resolve, place FAILED values when rejected
.then(success=>recur(files.slice(1),result.concat(success)))
}
return recur(files,[])
}
processImages(fs.readdirSync(storeDir)).then(results=>{
console.log('failed',results.filter(r=>r===FAILED).length)
});
For parallel processing you can use Promise.all:
Promise.all(
fs.readdirSync(storeDir).map((file)=> asyncInsertMagFromFile(file).catch(FAILED))
).then(results=>{
console.log('failed',results.filter(r=>r===FAILED).length)
})
Upvotes: 0
Reputation: 409
You can chain some 'then's one after another.
function asyncInsertMagFromFile(file) {
return new Promise((resolve, reject) => {
//some asynchronous processing with file
// call resolve when finished
resolve();
})
}
let chain = Promise.resolve();
fs.readdirSync(storeDir).forEach(function (file) {
chain = chain.then(((file) => () => asyncInsertMagFromFile(file))(file));
});
chain.then(() => {
//finished
}).catch((err) => {
//error in chain
})
Another way would be to use a for statement as mentioned in the comments:
function asyncInsertMagFromFile(file) {
return new Promise((resolve, reject) => {
//some asynchronous processing with file
// call resolve when finished
resolve();
})
}
(async () => {
const files = fs.readdirSync(storeDir);
for (let i = 0; i < files.length; i++) {
await asyncInsertMagFromFile(files[i]);
}
})()
Upvotes: 1
Reputation: 3550
This may help you;
async function asyncInsertMagFromFile(file) {
// use await to gather results from processing or return a promise
return result;
}
function mapRequests(storeDir) {
return fs.readdirSync(storeDir).map(async function(file) {
return await asyncInsertMagFromFile(file);
});
}
mapRequests(storeDir).then((mapped) => {});
The reason your example didn't work is because the forEach
handler function uses await
but is not declared async.
Upvotes: 1
Reputation: 731
await is only valid in async function
Use .map
instead of .forEach
, and pass it an async function as a callback.
Upvotes: 1
Reputation: 6749
You can try to use array.reduce to get a previous value (list of promises) and await it's completion before doing another call of the asyncInserMagFromFile function
(function loop() {
fs.readdirSync(storeDir).reduce(async (previousPromise, file) => {
await previousPromise;
return new Promise(resolve =>
asyncInsertMagFromFile(file, resolve);
);
},Promise.resolve());
})();
Upvotes: 1