I’m having an issue where my Promise.all is resolving too early. For a test I want to console.log the length of the array which is getting pushed from within the promise map but it is returning 0 sadly. I’m sure it’s something simple…
JavaScript
x
12
12
1
fromPath(job.data.path, { density: 100, format: "png" }).bulk(-1, true).then(output => {
2
Promise.all(output.map(page =>
3
jimp.read(Buffer.from(page.base64, 'base64')).then(img =>
4
{
5
img.invert().getBase64Async(jimp.AUTO).then(data => imageArray.push(data.replace('data:image/png;base64,', ''))).catch(err => console.log(err))
6
}
7
).catch(err => console.log(err))
8
)).catch(err => console.log(err))
9
}
10
// This returns early
11
).then(console.log(imageArray.length)).then(done()).catch(err => console.log(err));
12
Any help would be greatly appreciated.
Advertisement
Answer
There are a lot of issues there. Mainly they fall into these categories:
- Not returning the results of promise chains from fulfillment handlers, which means the chain the fulfillment handler is in won’t be linked up to the promise chain you created within it
- Calling functions and passing their return value into
then
, rather than passing a function intothen
See inline comments in this minimal, least-changes reworking of that code:
JavaScript
1
31
31
1
fromPath(job.data.path, { density: 100, format: "png" }).bulk(-1, true)
2
.then(output => {
3
// Return the result of `Promise.all`
4
return Promise.all(
5
output.map(
6
page => jimp.read(Buffer.from(page.base64, 'base64'))
7
.then(img => {
8
// Return the ersult of this promise chain
9
return img.invert().getBase64Async(jimp.AUTO)
10
.then(data => imageArray.push(data.replace('data:image/png;base64,', '')))
11
// This error handler does nothing useful, since we now return
12
// the promise chain
13
// .catch(err => console.log(err))
14
})
15
// Recommend **not** handling errors at this level, but using
16
// `Promise.allSettled` instead
17
.catch(err => console.log(err))
18
)
19
)
20
// This will only be reached if a *synchronous* error occurs calling (for instance)
21
// `getBase64Async`, since you've already caught errors above
22
.catch(err => console.log(err))
23
})
24
// Use a function here, don't call `console.log` directly
25
.then(() => console.log(imageArray.length))
26
// ^^^^^^
27
// Pass `done` directly to `then`, don't call it and pass its return value
28
// (e.g., remove the `()`)
29
.then(done) // Or `.then(() => done)` if you want `done` called with no arguments
30
.catch(err => console.log(err));
31
FWIW, though, if I had to not use async
functions I’d probably do it like this:
JavaScript
1
20
20
1
fromPath(job.data.path, { density: 100, format: "png" }).bulk(-1, true)
2
.then(output => Promise.allSettled(
3
output.map(
4
page => jimp.read(Buffer.from(page.base64, 'base64'))
5
.then(img => img.invert().getBase64Async(jimp.AUTO))
6
.then(data => {
7
imageArray.push(data.replace('data:image/png;base64,', ''));
8
})
9
)
10
))
11
.then(results => {
12
// Show errors
13
const errors = results.filter(({status}) => status === "rejected");
14
for (const {reason} of errors) {
15
console.error(reason);
16
}
17
// Done
18
done();
19
});
20