0

I know Array.prototype.map is a synchronous operation. On the other hand if the map function is a callback function (asynchronous) undefined will return immediately.

So my question is can the next function safely assume all callback functions have been done?
A sample code may make my question more clear :

results = files.map(file => {
  fs.readFile(file, (err, data) => {
    if (err) throw err;
    return process(file) //will return the processed value, NOT a promise
  });
)
//I know results will be [undefined, undefined, undefined ...]
//But can I assume all the files have been processed if I reach here?
console.log('done')

I don't care about the return values. That is why I don't want to bother with await/async. I just want to make sure all callback functions have called and returned. Is that possible ?

------- update --------

In additional to the answer I found these articles also help me understand the problem: https://medium.com/@antonioval/making-array-iteration-easy-when-using-async-await-6315c3225838
Using async/await with a forEach loop

I have to use promise to make sure all callback iteratees have finished. So using bluebird promise.map helps to reduce boilerplate codes

Qiulang
  • 10,295
  • 11
  • 80
  • 129
  • You actually `return` nothing from the arrow func, therefore it is undefined, if you return the promise you could use `Promise.all` on the returned array. – Jonas Wilms Oct 13 '18 at 15:02
  • I don't want to use await b/c I can't care about the mapped array I just want to know if all callback functions are returned. What is the "correct" way to do it ? – Qiulang Oct 13 '18 at 15:05
  • @JonasWilms my sample code was wrong (I have corrected it) I do return in my arrow function but I believe I still get an array with all undefined items. I think my question is different from what you mentioned in the other two questions. – Qiulang Oct 13 '18 at 15:11
  • 1
    Agreed, its not a real dupe, apologies – Jonas Wilms Oct 13 '18 at 15:45
  • 1
    @Qiulang no, `map` does not ensure that any callbacks have been called, in fact, it *doesn't even know* about the asynchronous callbacks you passed to `readFile`. It only cares about the return value of the `map` callback itself, which is `undefined`. Just go and use promises, you still can ignore their results - but you need them to be able to wait for them. – Bergi Oct 14 '18 at 14:57
  • @Bergi double confirm., thanks! – Qiulang Oct 14 '18 at 15:05

1 Answers1

1

You have to make the callback function promising, then you can use Promise.all:

 const results = Promise.all(files.map(file => new Promise(resolve => {
  fs.readFile(file, (err, data) => {
    if (err) throw err;
    resolve(process(file));
  });
 ));

 results.then(() => {
   console.log('done')
   //...
 });
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
  • That is what I have been trying to avoid in the first place. I know I can use promise.all/await but I don't want to! Because all I need is to make sure the next function after map can safely assume all callbacks have done and hence the question. – Qiulang Oct 13 '18 at 15:52
  • @qiulang this is the only way. Or you use `fs.readFileSync` but that would be very slow – Jonas Wilms Oct 13 '18 at 15:55
  • But I did some test, e.g. print the processed value before return in each callback and found those prints always run before my next function. I know I shouldn't count on that but on the other hand b/c map is sync and I still wonder if that is the possible – Qiulang Oct 13 '18 at 15:59
  • @quilang as I said, if you want it to run synchronously use `fs.readFileSync` – Jonas Wilms Oct 13 '18 at 16:01