我想在while循环中的setTimeout中执行nodejs执行。我使用了async-waterfall函数,但它在循环中没有工作。所以我使用下面的代码: -
var i = 3;
while(i> 0)
{
setTimeout(function(){
console.log('start', i);
setTimeout(function(){ console.log('timeout');}, 1000);
console.log('end', i);
i--;
}, 1000);
}
console.log("execution ends");
但我没有得到预期的输出。 我的预期输出将如下: -
start3
timeout
end3
start2
timeout
end2
start1
timeout
end1
execution ends
答案 0 :(得分:0)
nodejs本质上是异步的,setTimeout
或多或少像在新线程上执行某些东西(或多或少因为JS是单线程并使用事件循环)。
查看这个npm包: https://www.npmjs.com/package/sleep
这应该可以解决问题......
但显然你应该只使用sleep
进行调试。
在生产代码中,您最好使用NodeJS的异步性质并使用Promises
查看此内容以获取更多详情: 事件循环:https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop
setTimeout:https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout
承诺:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
答案 1 :(得分:0)
方式1:使用while loop
var i = 3
var p = Promise.resolve(i)
while (i > 0) {
(i => {
p = p.then(() => {
return new Promise(function (resolve, reject) {
console.log('start', i)
setTimeout(function () {
console.log('timeout')
console.log('end', i)
resolve()
}, 1000)
})
})
})(i)
i--
}
p = p.then(data => console.log('execution ends'))

way2:
function test(i) {
console.log('start', i)
setTimeout(() => {
console.log('timeout')
console.log('end', i)
i--
if (i < 0) {
return
}
test(i)
}, 1000)
}
test(3);
&#13;
way3:使用async
async function test (i) {
console.log('start', i)
await new Promise(function (resolve, reject) {
setTimeout(() => {
console.log('timeout')
console.log('end', i)
i--
if (i < 0) {
reject(i)
}
resolve(i)
}, 1000)
})
.then(i => test(i))
.catch(i => console.log('done', i))
}
test(3)
&#13;
答案 2 :(得分:0)
您的程序w.r.t与您的预期输出存在一些问题。第一个i--仅在1000ms后才能工作。到那时,太多的while循环会运行。 setTimeOut
也是非阻止的,因此即使在第一个execution ends
被安慰之前,start
也会被安慰。要达到预期的结果,您可以对代码进行一些更改:
var i = 3;var j =3;
while(j> 0)
{
setTimeout(function(){
console.log('start', i);
console.log('timeout');
console.log('end', i);
i--;
}, 1000);
j--;
}
if(j == 0){
setTimeout(function(){
console.log('execution ends');
}, 1000);
}
答案 3 :(得分:0)
请尝试下面的代码段。您可以在timer方法中引入API调用或异步调用来代替setTimeout。
const timer = () => {
return new Promise(res => {
setTimeout(() => {
console.log('timeout');
res();
}, 1000);
});
}
let i = 3;
let temp;
while (i > 0) {
if (temp !== i) {
temp = i;
console.log('start', temp);
timer().then(() => {
console.log('end', temp);
i -= 1;
});
}
}
答案 4 :(得分:0)
首先,您必须了解Javascript中的setTimeout()
是非阻止的。这意味着它所做的只是安排稍后运行的东西,然后其余代码立即继续运行。
在你的特定代码示例中,你将有一个无限循环,因为while循环一直持续,继续安排越来越多的计时器,但是直到while循环停止,这些计时器都不会运行。并且,在其中一个计时器运行之前,您的循环变量i
永远不会被更改,因此while
循环永远不会停止。
要理解为什么它以这种方式工作,你必须要了解Javascript和node.js的事件驱动设计。当你调用setTimeout()
时,它会调度JS引擎内部的内部计时器。当该计时器触发时,它会在Javascript事件队列中插入一个事件。下一次JS解释器完成它正在做的事情时,它将检查事件队列并将下一个事件拉出队列并运行它。但是,您的while
循环永远不会停止,因此它无法进入任何新事件,因此它永远不会运行任何计时器事件。
我将向您展示三种不同的生成所需输出的方法,它们都在可运行的代码片段中,因此您可以在答案中直接运行它们以查看其结果。
第一种技术是通过简单的Javascript完成的,只需在未来的不同时间设置定时器,使各种所需的输出以正确的顺序触发:
改变计时器
let cntr = 3;
for (let i = 1; i <= 3; i++) {
// schedule timers at different increasing delays
setTimeout(function() {
console.log('start', cntr);
setTimeout(function() {
console.log('timeout');
console.log('end', cntr);
--cntr;
if (cntr === 0) {
console.log("execution ends");
}
}, 1000);
}, i * 2000);
}
&#13;
或者,如果你真的希望它是while
循环:
let cntr = 3, i = 1;
while (i <= 3) {
// schedule timers at different increasing delays
setTimeout(function() {
console.log('start', cntr);
setTimeout(function() {
console.log('timeout');
console.log('end', cntr);
--cntr;
if (cntr === 0) {
console.log("execution ends");
}
}, 1000);
}, i * 2000);
i++;
}
&#13;
使用Promise来排序操作
function delay(t, v) {
return new Promise(resolve => {
setTimeout(resolve.bind(null, v), t);
});
}
function run(i) {
return delay(1000).then(() => {
console.log("start", i);
return delay(1000).then(() => {
console.log("timeout");
console.log("end", i);
return i - 1;
});
});
}
run(3).then(run).then(run).then(() => {
console.log("execution ends");
});
&#13;
如果您愿意,也可以将其置于循环中:
function delay(t, v) {
return new Promise(resolve => {
setTimeout(resolve.bind(null, v), t);
});
}
function run(i) {
return delay(1000).then(() => {
console.log("start", i);
return delay(1000).then(() => {
console.log("timeout");
console.log("end", i);
return i - 1;
});
});
}
[3, 2, 1].reduce((p, v) => {
return p.then(() => {
return run(v);
});
}, Promise.resolve()).then(() => {
console.log("execution ends");
});
&#13;
Promises Plus ES7 Async / Await
此方法使用ES7的await
功能,允许您使用promises和await
编写类似顺序的代码,这可以使这些类型的循环更加简单。 await
在等待承诺解析时阻止函数的内部执行。它不会阻止函数的外部返回。该功能仍然立即返回。它返回一个promise,当内部函数的所有被阻塞的部分完成时,它将被解析。这就是为什么我们在.then()
的结果上使用runSequence()
知道它何时完成的原因。
function delay(t, v) {
return new Promise(resolve => {
setTimeout(resolve.bind(null, v), t);
});
}
async function runSequence(num) {
for (let i = num; i > 0; i--) {
await delay(1000);
console.log("start", i);
await delay(1000);
console.log("timeout");
console.log("end", i);
}
}
runSequence(3).then(() => {
console.log("execution ends");
});
&#13;
此await
示例说明了promises和await
如何简化ES7中的操作顺序。但是,他们仍然要求您了解异步操作如何在Javascript中工作,所以请不要试图首先跳过这种理解水平。
答案 5 :(得分:-1)
你没有得到预期的输出,因为代码中有关闭,改进你的代码:
var i = 3;
while(i> 0)
{
setTimeout((
function(i){
return function(){
console.log('start', i);
setTimeout(function(){ console.log('timeout');}, 1000);
console.log('end', i);
i--;
}
}
)(i), 1000);
}