J. Cake
J. Cake

Reputation: 351

How does Javascript know if there has been an error when executing a function (callbacks)

So I am reading about callbacks because I´m learning backend development on Node.js, and in several webs they say this good practice about writing callbacks with error argument as its first argument:

For example:

fs.readFile('/foo.txt', function(err, data) {
  // If an error occurred, handle it (throw, propagate, etc)
  if(err) {
    console.log('Unknown Error');
    return;
  }
  // Otherwise, log the file contents
  console.log(data);
});

Ok sure, I think I understand it clearly what is happening. If once the module fs finishes reading the file "foo.text" there is an error, then the callback function executes console.log("Uknown error") but how Javascript / Node knows that the variable err corresponds to an error in the code??

Because If i name it error instead of err , I imagine it also works right? And what If put it in the second argument? I imagine then it wouldn´t work. Is that it? If its why it is called a good practice if there is no other way to put the error argument but in the first place.

Upvotes: 1

Views: 46

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074535

but how Javascript / Node knows that the variable err corresponds to an error in the code??

By convention. The way readFile (and other Node.js callback-style functions) are written, they call their callback with the error as the first argument, or null as the first argument. The name of that parameter in the function signature is irrelevant (you can call it anything you like; err, e, and error are all common). It's the fact it's the first parameter that matters, because it will receive the first argument when called.

In these modern times, though, things are moving away from Node.js callback-style APIs and toward APIs using Promises, which make the error and success paths much more distinct. Then async/await syntax is layered on top of promises to make it possible to write asynchronous code using the standard logical flow control structures.

Node.js callback style (like your code):

const fs = require("fs");

// ...

fs.readFile('/foo.txt', function(err, data) {
    // If an error occurred, handle it (throw, propagate, etc)
    if (err) {
        // It failed
        console.log(err);
        return;
    }
    // It worked
    console.log(data);
});

With promises via the fs.promises API:

const fsp = require("fs").promises;

// ...

fsp.readFile('/foo.txt')
.then(data => {
    // It worked
    console.log(data);
})
.catch(err => {
    console.log(err);
});

Of course, you may not handle errors at that level; you might instead return the result of calling then so that the caller can chain off it and handle errors (or pass it off to its caller, etc.).

With async/await (this must be inside an async function, although in modules top-level await is coming):

const fsp = require("fs").promises;

// ...inside an `async` function:

try {
    const data = await fsp.readFile('/foo.txt');
} catch (err) {
    console.log(err);
}

And again, you might not handle errors at that level; you might let them propagate and have the caller handle them (or the caller might let them propgate to its caller to handle them, etc.).

Not all of Node.js's API has promises yet. You can wrap a single callback-style API function with promises via util.promisify; you can wrap an entire API via various npm modules like promisify.

Upvotes: 2

Related Questions