在使用nodejs制作链接简化程序脚本时,遇到以下问题: 我的程序进入无限循环,原因是我忽略了 这是代码:
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个字符),然后,如果存在,我创建另一个字符串,依此类推..直到找到一个未被使用的字符串(数据库为空btw,所以有它没有理由进入无限循环)。
答案 0 :(得分:0)
您可以使用async/await
遍历并测试数据库中的值。我们要做的是将您的函数转换为异步函数,然后创建一个新函数,该函数将返回将解决true/false
的Promise。
接下来,我们在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);
});
});
答案 1 :(得分:0)
请勿混用同步循环和异步条件更新。这样的事情可以保证在while
调用返回结果之前,尽可能多地运行DoSomething
正文:
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();
});
}
答案 2 :(得分:0)
while
循环是同步运行的,这意味着它们会阻止线程继续执行直到完成。由于链接缩短器是异步的,因此被while
循环阻止。
要异步处理此代码,您可以返回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