请问在Nodejs循环里面已经使用return,但是循环会继续执行,是什么原因?

请问在Nodejs循环里面已经使用return,但是循环会继续执行,是什么原因?

      if (order.length) {
for (var i = 0; i < order.length; i++) {
(function (i) {
mysqldb.query(
“SELECT goods_name FROM order_goods WHERE order_id =?”, [order[i].order_id],
function (err, rows) {
if (err) {
req.session.error = ‘出错了’;
return res.redirect(’/checkcode’);
}
//console.log(rows);
order[i].goods_name = rows
order[i].appointment_time = getLocalTime(order[i].appointment_time);

            if (i == (order.length - 1)) {
              console.log("ok");

              return res.render(tep, {
                title: '订单',
                order: order
              });
            }
          }
        );
      })(i);
    }
  }

当发生错误时执行到这条语句

if (err) {
      req.session.error = '出错了';
      return res.redirect('/checkcode');
 }

这里已经return 了,但是程序依然会继续执行,请问是什么原因导致?难道node中的return 不能终止语句?谢谢!


3 回复

在Node.js中,return语句只能用于终止当前函数的执行。然而,在异步操作(如数据库查询)中,return并不能阻止后续代码的执行,因为这些异步操作是在未来的某个时刻完成的,并不会立即阻断当前函数的执行。

在你的例子中,mysqldb.query 是一个异步操作。即使你在错误处理部分使用了 return,查询操作仍然会在后台执行,并且回调函数也会在查询完成后被调用。因此,尽管你希望在遇到错误时直接返回并重定向用户,但实际的执行流程并不会因此而停止。

示例代码

if (order.length) {
    for (var i = 0; i < order.length; i++) {
        (function (i) {
            mysqldb.query(
                "SELECT goods_name FROM order_goods WHERE order_id =?", [order[i].order_id],
                function (err, rows) {
                    if (err) {
                        req.session.error = '出错了';
                        return res.redirect('/checkcode'); // 这里返回只会影响当前回调函数
                    }
                    order[i].goods_name = rows;
                    order[i].appointment_time = getLocalTime(order[i].appointment_time);

                    if (i == (order.length - 1)) {
                        console.log("ok");
                        res.render('tep', {
                            title: '订单',
                            order: order
                        });
                    }
                }
            );
        })(i);
    }
}

解释

  1. 异步操作mysqldb.query 是一个异步操作,这意味着它不会阻塞代码的执行。
  2. 回调函数:当查询完成后,回调函数会被调用,无论之前是否有 return 语句。
  3. 控制流:由于异步操作的存在,return 只能在当前的回调函数内部起作用,而不会影响外部循环的执行。

如何解决

如果你希望在遇到错误时完全停止后续的异步操作,可以考虑使用一些控制流程库,例如 async 或者 Promise 来管理异步操作的顺序和依赖关系。

例如,使用 async 库:

const async = require('async');

async.eachSeries(order, function(item, callback) {
    mysqldb.query(
        "SELECT goods_name FROM order_goods WHERE order_id =?", [item.order_id],
        function(err, rows) {
            if (err) {
                req.session.error = '出错了';
                return callback(new Error('出错了'));
            }
            item.goods_name = rows;
            item.appointment_time = getLocalTime(item.appointment_time);
            callback();
        }
    );
}, function(err) {
    if (err) {
        return res.redirect('/checkcode');
    }
    res.render('tep', {
        title: '订单',
        order: order
    });
});

这样可以确保每个查询都按顺序执行,并且在遇到错误时可以及时停止后续操作。


怎么个继续执行?return只结束当前函数,外层函数是不会结束的,任何语言都一样

在Node.js中,return语句只能终止当前函数的执行,而不会终止外部的循环或其他异步操作。你遇到的问题是因为数据库查询是异步的,return语句只能终止回调函数内部的执行流程,而不会影响到外部的循环。

为了更好地理解这个问题,可以看一个简化版的示例:

for (let i = 0; i < 3; i++) {
  (function(i) {
    setTimeout(() => {
      console.log(`Loop iteration ${i}`);
      return; // 只能终止setTimeout内的执行
    }, 100);
  })(i);
}

在这个例子中,return只会影响定时器内部的执行,而不会终止循环。

对于你的问题,可以考虑使用Promiseasync/await来更好地处理异步操作。例如:

async function processOrders() {
  if (order.length) {
    for (let i = 0; i < order.length; i++) {
      const result = await new Promise((resolve, reject) => {
        mysqldb.query(
          "SELECT goods_name FROM order_goods WHERE order_id=?", [order[i].order_id],
          function (err, rows) {
            if (err) {
              reject(err);
            } else {
              resolve(rows);
            }
          }
        );
      });

      order[i].goods_name = result;
      order[i].appointment_time = getLocalTime(order[i].appointment_time);

      if (i === order.length - 1) {
        console.log("ok");
        res.render('tep', { title: '订单', order: order });
      }
    }
  }
}

processOrders().catch(err => {
  req.session.error = '出错了';
  res.redirect('/checkcode');
});

这样可以更清晰地处理异步操作,并且可以在需要的地方使用return来提前退出函数。

回到顶部