For example we have a function to check the filesize:
const fs = require('fs'); function fileSize (fileName, cb) { if (typeof fileName !== 'string') { throw new TypeError('filename should be string') } fs.stat(fileName, (err, stats) => { if (err) { return cb(err) } cb(null, stats.size); }); } fileSize(__filename, (err, size) => { if (err) throw err; console.log(`Size in KB: ${size/1024}`); }); console.log('Hello!'); /* Hello! Size in KB: 0.44921875 */
It works fine, but the 'fileSize' function has a problem,
if (typeof fileName !== 'string') { return new TypeError('filename should be string') }
those part of code run in sync, not async, but the rest part of code for 'fileSize' is aysnc function. Normally a function should be always sync or async.
Why? If we call the fileSize with wrong params:
fileSize(1, (err, size) => { if (err) throw err; console.log(`Size in KB: ${size/1024}`); });
It ouput:
/* throw new TypeError('filename should be string') ^ TypeError: filename should be string */
Our console.log() is not running...
To fix it we can use 'process.nextTick', it run before 'event loop' and right after 'call stack is empty':
const fs = require('fs'); function fileSize (fileName, cb) { if (typeof fileName !== 'string') { return process.nextTick( cb, new TypeError('filename should be string') ) } fs.stat(fileName, (err, stats) => { if (err) { return cb(err) } cb(null, stats.size); }); } fileSize(1, (err, size) => { if (err) throw err; console.log(`Size in KB: ${size/1024}`); }); console.log('Hello!'); /* Hello! C:Usersz000879learnmaybesrcprocess.js:21 if (err) throw err; ^ TypeError: filename should be string */
This time, our 'Hello' was printed out before error was throw.