Nodejs 中的无限循环

Infinite loop in Nodejs

在使用 nodejs 制作 link Shortner 脚本时,我遇到了以下问题: 由于我忽略的原因,我的程序进入无限循环 这是代码:

function makeShort() {
    var short = "";
    var cond = true;

    while(cond){
        var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

        for(var i = 0; i < length; i++){
            short += possible.charAt(Math.floor(Math.random() * possible.length));
        }

        let query = {short:short};

        Link.findOne(query, (err, link)=>{
            if(err) throw err;
            if(!link){
                console.log("here");
                cond = false;

            }
        });
    }
    return short;
}

然后在这里使用它:

router.post('/', (req, res)=>{
    let short = makeShort();
    const newLink = new Link({
        url: req.body.url,
        short:short
    });

    newLink.save().then(link => {
        res.json(link);
    });
});

我的想法是我生成一个随机字符串(5 个字符),然后,如果它存在,我创建另一个,依此类推。直到我找到一个未使用的字符串(顺便说一句,数据库是空的,所以它没有理由进入无限循环)。

您可以使用 async/await 循环并测试数据库中的值。我们所做的是将您的函数转换为异步函数,然后创建一个新函数,该函数将 return 一个将解析 true/false 的承诺。

接下来我们在 while 循环和 await 中调用该函数以获得包含 true/false 的结果,然后我们将其设置为变量 cond 并继续循环。

看起来像这样:

async function makeShort(length) {
  let cond = true;

  while (cond) {
    let short = (Math.random() * 1000).toString(32).replace(/\./g, '').substr(0, length);

    let query = { short: short };
    cond = await findOne(query);
  }
  return short;
}

function findOne(query) {
  return new Promise(resolve => {
    Link.findOne(query, (err, link) => {
      if (err) resolve(false);
      if (!link) {
        return resolve(false);
      }
      return resolve(true);
    });
  })
}

然后我们可以像这样使用 let short = await makeShort() 调用它(我们还必须使用 make (req, res) 函数 async):

router.post('/', async (req, res) => {
  let short = await makeShort();
  const newLink = new Link({
    url: req.body.url,
    short: short
  });

  newLink.save().then(link => {
    res.json(link);
  });
});

不要混用同步循环和异步条件更新。在 DoSomething 调用 returns 结果之前,保证 运行 while 主体尽可能多地使用类似的东西:

while(cond) {
  // call something async. don't wait for a result.
  DoSomething.asynchronous( () => { cond = false; });
  // then immediately restart the iteration
}

所以不要那样做。让你的 makeShort 异步生成一个简短的字符串。

const symbols = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
const symbolCount = symbols.length;

function makeShort(howMany) {
  howMany = howMany || 5;
  let short = "";
  while(howMany--) {
    short += symbols[(Math.random() * symbolCount)|0];
  }
  return short;
}

然后,独立于此进行验证:

function assignShortForm(req, res) {
  let short = makeShort();

  verifyShortIsAvailable(
    short,
    success => {
      // this short form was available
      new Link({ url: req.body.url, short }).save().then(link => res.json(link));
    }, error => {
      // try again. RNG is not your friend, and this COULD run a very long time.
      assignShortForm(req, res);          
    }
  );
}

您的路由器使用该功能,而不是内联它:

router.post('/', assignShortForm);

在此,verifyShortIsAvailable 应异步执行其工作:

verify verifyShortIsAvailable(short, resolve, reject) {
  Link.findOne(query, (err, link) => {
    if (err) return reject(err);
    if (link) return reject("...");
    return resolve();
  });
}

while 同步循环 运行,这意味着它们会阻止线程进一步执行,直到它们完成。因为 link 缩短器是异步的,它被 while 循环阻塞。

要异步处理此代码,您可以 return a Promise

function makeShort() {

    var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    // note length was previously undefined in the comparison. use possible.length or another arbitrary value
    for(var i = 0; i < possible.length; i++){
        short += possible.charAt(Math.floor(Math.random() * possible.length));
    }

    let query = {short:short};
    return new Promise((resolve, reject) => {
        Link.findOne(query, (err, link) => {
            if(err) return reject(err);
            resolve(link)
        });
    })
}

然后就可以这样使用了...

let short = makeShort().then(shortLink => {
    // do something with the link
}).catch(err => {
    // handle the error
});

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises