A-yon Lee
A-yon Lee

Reputation: 2202

js function does not return when condition fulfills

The following code, I cannot find any problem out, but yet, it sometimes output "'i' should not be higher than handlers.length".

function callNext(req, res, handlers, cb) {
    let i = -1;
    let next = (thisObj) => {
        i += 1;

        if (i == handlers.length) {
            return cb();
        } else if (i > handlers.length) {
            console.log("'i' should not be higher than handlers.length.");
            console.log(handlers.length, i); // => 9 10
            return;
        }

        try {
            return handlers[i].call(thisObj || this, req, res, next);
        } catch (e) {
            this.onerror(e, req, res);
        }
    };

    return next();
}

Because based on human logic, the function is returned when i is equal to handlers.length, and the code below should never run, this problem really drives me nut.

Upvotes: 1

Views: 53

Answers (2)

Kosh
Kosh

Reputation: 18378

It happens because i will increment on the next call after if (i == handlers.length) return cb(); and become handlers.length + 1

You have to do

    if (i >= handlers.length) {
        return cb();
    }

or something like this.

Upvotes: 0

Jiby Jose
Jiby Jose

Reputation: 3845

The easiest assumption is that some of the handlers wrongly call next twice.

Generally i would recommend to safeguard again this anyways, you could use something like

function callNext(req, res, handlers, cb) {
   let lastCalledIndex;
   let next = (thisObj, index) => {
       if (index === lastCalledIndex) { 
           console.log("'next' called multiple times from handler");
           return; 
       }
       lastCalledIndex = index;
       if (i === handlers.length) {
           return cb();
       } else if (index > handlers.length) {
           console.log("'index' should not be higher than handlers.length.");
           console.log(handlers.length, index); // => 9 10
           return;
       }

       try {
           return handlers[index].call(thisObj || this, req, res, next.bind(undefined, thisObj, index + 1));
       } catch (e) {
           this.onerror(e, req, res);
       }
    };

    return next(this, 0);
}

Upvotes: 1

Related Questions