1

I would like to avoid using timeout to display the final result of a series of asynchronous operations. Without the setTimeout when I print at the end of the while, the array is empty. The problem is clear being asynchronous operations. I could not find an alternative solution to using the timeout while keeping the cb-style (without promise)

    const fs = require('fs')
    
    function leggi_file(){
        let files = ['a','b','c','d']
        let totale = []
        while(true){
            let file=files.shift()
            if (file) fs.readFile(file,(err,data)=>{
                if (err){
                    console.error(err)
                    return
                }else totale.push(data)
            })
            else {
                setTimeout(()=>console.log(totale),300)
                break}
        }
    }
    leggi_file()
  • Why are you trying to avoid promises? It's the simple, efficient, and idiomatic solution without any pitfalls. – Bergi Jun 17 '21 at 16:17

2 Answers2

0

The general approach would be something along these lines:

Create somewhere to store some flags associated with something that can identify if the associated asynchronous operation has finished.

It looks like you could use an object with the file paths and keys and booleans as the values.

Every time you start an asynchronous operation add the file path to the object with a value of false.

Every time you finish one, set the property for that path to true and loop over the entire object until you either get to the end (in which case do whatever work you want to when everything is done) or you find a value which is false (in which case stop and wait for the next asynchronous operation to finish and do the same thing).


It would probably be easier to wrap your functions in promises and use Promise.all though. Wheel reinvention is a waste of time.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • You wouldn't actually loop over flags every time, you'd just use a counter and then run your callback when it has reached the number of started tasks. – Bergi Jun 17 '21 at 16:18
0

This function will take a list of the files in string format and a callback which will be called with a list of object, in which each object contains the filename, data of that file, and any error which occur while reading the file.

We have to wait until all the callBacks are resolved. Only after that we will call the callback.

function readAllFiles(files, lastCallBack) {
  const processedFilesWithData = [];
  
  files.forEach(file => fs.readFile(file, (error, data) => {
    processedFilesWithData.push({data, file, error});
    if(processedFilesWithData.length === files.length) {
      lastCallBack([...processedFilesWithData])
    }
  }));
}

An example of how to use it.

readAllFiles(['file1', 'file2'], console.log)
  • "*you can handle your error condition here instead of handling it the main code*" - no, you can't. The error should need to be handled in the main code only once. `readAllFiles` doesn't work if there's an error - it will just never call `lastCallback` or signal in any way that it has finished. – Bergi Jun 17 '21 at 16:20
  • yeah it will never call the last callBack with the errors that happened per file. It would be good to return them also per file. thanks. – Sukhdev Singh Jun 17 '21 at 16:32