Backward-compatible done()

I am in the process of making our nodes implement the new on('input') signature of Node-RED v1.0. I also noticed the error handling is now done via done(err) instead of node.error(err, msg).

If there are multiple return points or error handling locations, the proposed way from the docs and the blog can be quite verbose, because you'd always have to check if done is defined.

So I did the same as Nick (@knolleary ) did with send for the done callback.

It's working in both pre-1.0 and 1.0 for me. The question is, did I overlook some edge cases?
If it's an approved solution, maybe this could be added to the docs as well. :slightly_smiling_face:

Here's the verbose commented version:

done = done || function () {

    // at least one argument -> 'done' is used as error notification
    if (arguments.length > 0) {
        // call node.error()
        // use first arg as error object
        // 'msg' is taken from closure
        node.error.apply(node, [arguments[0], msg]);
    }

    // otherwise do nothing
};

And the modified example from the blog with the new done as one-liner:

this.on('input', function (msg, send, done) {
    // If this is pre-1.0, 'send' will be undefined, so fallback to node.send
    send = send || function () { node.send.apply(node, arguments) }
    done = done || function () { if (arguments.length > 0) { node.error.apply(node, [arguments[0], msg]); } };

    // do some work with msg
    someImaginaryLibrary(msg, (err, result) => {
        if (err) {
            // Report back the error
            done(err);
        } else {
            msg.payload = result;
            send(msg);
            done();
        }
    })
})
2 Likes

Here is how I do it at the moment:

// If this is pre-1.0, 'send' will be undefined, so fallback to node.send
send = send || function() { node.send.apply(node,arguments) }
// If this is pre-1.0, 'done' will be undefined, so fallback to dummy function
done = done || function() { if (arguments.length>0) node.error.apply(node,arguments) }
3 Likes

Do you call it with both error and msg arguments as done(err, msg)? Otherwise catch nodes won't be triggered.

Yes, same as yourself.

No, there is a slight difference. :slightly_smiling_face:

I call done(err). The message is added from the closure in my wrapper function.

The reason was forward compatibility, if the actual done ever accepted more than one argument in the future. I tried to keep the API as-is.

In truth, I don't believe I've ever actually need to error out. All of my "errors" either recover or deliberately stop Node-RED because they wouldn't allow the node to continue. Those errors are generally only ever in the initial setup of the node.

Not to say that I shouldn't use it, just not used it so far.

I actually use catch nodes and proper error handling a lot, to get sort of a try/catch block.

At least it's important for our flows at work, because we have to return some meaningful response to the PLCs we're communicating with. Even if it's an error message. The operator needs to know what's going on. Not handling these would just result in a timeout, because the flow never finishes otherwise.

So all of our specialized custom nodes throw proper errors that can be handled accordingly.

2 Likes