I had a requirement to read multiple files in one go in Node.js project.
Requirement:
- Read UTF8 files asynchronously.
- Notify when each file read is done.
- Notify when reading all files is done.
I have found few examples on Stackoverflow:
- Asynchronously reading and caching multiple files in nodejs
- Reading and returning multiple files in Node.js using fs.readFile
In both cases answer was to use either async
library or to just use native node.js functions.
I don’t like using external library and I am trying to use native/vanilla as much as possible. If there is one small part of external/third-party library that I have to use, I’d rather write my own. For example, if I have to get reference to DOM element by id
on web page, I’d avoid using jQuery. If I would have to heavily traverse the DOM then I would definitely use jQuery.
So, I will skip using async
library and use only native functions.
Here is complete code that we will go through:
Latest version of file is in repository on Github: multiread.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
|
TL;DR
batch
function
The idea behind batch
function was to have generic function that will execute array of asynchronous functions and wait for them to finish, something like what async
doing, as long as signature of function is function([parameters], callback)
.
Parameter description:
execFunc
– function that is suppose to be executed for each argument set. In this caseexecFunc
isfs.readFile
.args
– array of ‘argument sets’ for each execution => ‘argument set’ is array of arguments without callback. In this case, set contains file path and encoding.eachCallback
– callback for eachexecFunc
call.callback
– callback when all is done.
Inside batch
function there are two functions: cb
and iterate
.
iterate
function does actual call to execFunc
. It will add cb
function to collection arguments at last position to act as actual callback of execFunc
. This way we control each callback of execFunc
and notify outside world when we want that it’s all done. Also, this method will queue execution of asynchronous functions i.e. making them execute sequentially.
cb
function is a execFunc
callback. As arguments of function are actual result of execFunc
execution, this is the place where we will catch it.
In batch
function level, there is results
array that will hold all results returned from execFunc
executions. This array will be an argument for final callback call. results
array is populated here on each call.
Then, we will call eachCallback
function to notify outside world that execution of execFunc
is done.
Then, we will check if this was a last execFunc
call. If yes, call final callback
sending all results as an argument. If no, continue iteration.
batchRead
function
batchRead
function wrapping a call to batch
function to simplify call to generic batch
function.
Parameter description:
files
– array of file paths to be read.eachCallback
– callback for eachfs.readFile
call.callback
– callback when all is done.
As batch
function is accepting object[object[]]
array for arguments, we need to repack file paths array to new array. Also, in each of these arrays, we will add additional argument => utf8
.
Then, we are calling batch
function with all appropriate arguments.
batchRead
call
At the end, we will call batchRead
. eachCallback
should have same signature as you would use when calling fs.readFile
.
Summary
If you have to call same function with different arguments several times, queue each call and have final callback, you can use batch
function. batchRead
shows how batch
function can be utilized by reading multiple files sequentially and notifying the application when all is done.
HTH