Javascript console.log(';\n';);在为循环的内部设置超时后

Javascript console.log(';\n';);在为循环的内部设置超时后,javascript,Javascript,我正在学习async,并尝试使用setTimeout打印一个延迟50毫秒的字符串,最后在循环完成后打印一个换行符 const str = "hello world"; let ms = 0; for (let char of str) { setTimeout(() => { process.stdout.write(char); }, ms); ms += 50; } console.log('\n'); 使用我当前的代码,它会在循环完成之前打

我正在学习async,并尝试使用
setTimeout
打印一个延迟50毫秒的字符串,最后在循环完成后打印一个换行符

const str = "hello world";
let ms = 0;

for (let char of str) {
  setTimeout(() => {
    process.stdout.write(char);
  }, ms);
  ms += 50;
}
console.log('\n');
使用我当前的代码,它会在循环完成之前打印换行符

const str = "hello world";
let ms = 0;

for (let char of str) {
  setTimeout(() => {
    process.stdout.write(char);
  }, ms);
  ms += 50;
}
console.log('\n');

时间太少了,你看不出有什么不同。使用500而不是50。 注:1000毫秒=1秒。

const str=“hello world\n”;
设ms=0;
for(str的let char){
设置超时(()=>{
process.stdout.write(char);
},ms);
ms+=50;
}
const sleep=ms=>{
返回新承诺(resolve=>setTimeout(resolve,ms));
}
常量printSomethingDelayed=myString=>{
返回sleep(200),然后返回(v=>console.log(myString));
}
常量forLoop=async\ux=>{
console.log('Start');
const myString=“你好,世界”;
for(让index=0;indexforLoop()
您可以使用
promise
async
wait
进行此操作。下面是使用
promise
的示例

const str=“你好世界”;
设ms=0;
for(str的let char){
变化(字符,毫秒);
ms+=50;
}
函数更改(字符,毫秒){
返回新承诺(函数(解析、拒绝){
设置超时(()=>{
console.log(char);
解决(“完成”)
},ms);
}).then(函数(){
console.log(“\n”)
}); 

}
异步编程就是这样工作的:-)

在JavaScript中,每个块都被同步地推送到堆栈中,然后块被执行。但是,只要堆栈将任何块识别为WebAPI的函数(在本例中为
setTimeout
),堆栈就会将其交给浏览器来处理执行

浏览器完成任务后,它们将被推回堆栈(称为
回调
)。当堆栈为空时,这些回调函数由堆栈执行

在给定的示例中,当stack看到setTimeout函数时,它将移交给浏览器执行,并移动到下一个块,即
console.log()
,然后执行它。现在堆栈是空的,可以执行回调函数了

如果要在设置超时后打印控制台日志,可以使用
promises
async wait


如果您想了解更多关于异步编程的信息,请务必在JSConfEU上查看Philip Roberts的

setTimeout(与ES6之前的所有异步函数一样)不是JavaScript引擎的一部分,因此当解析器遇到它时,它不会进入常规调用堆栈。相反,setTimeout安排浏览器API调用,然后解析器继续

因此,当解析器在for循环中遇到所有的“settimeout”时,浏览器将进行API调用,我们正在进行下一步。在您的案例中,下一件事恰好是console.log()。它进入常规调用堆栈并执行

同时,浏览器正在进行一个API调用,setTimeout的结果被放入一个称为回调队列的东西中。函数的返回将按预期顺序排列在那里

现在,调用堆栈已清除。这里是有趣的部分。一种叫做事件循环的东西不断地检查,检查,看看调用堆栈是否清晰。如果是,它将查看回调队列。然后,事件循环将回调队列返回的函数放入调用堆栈,并按顺序执行

这是很多信息,坦率地说,我认为这里的任何答案都不足以巩固这种理解,所以我强烈推荐这段关于这个主题的youtube视频:。这段视频为这种精确的行为提供了合适的心理模型。

const str=“你好世界”;
设ms=0;
常量打印=功能(i、ms、str){
常数c=str.charAt(i);
如果(!c){
console.log('\n');
}
否则{
setTimeout(函数(){
控制台日志(c);
打印(i+1,ms+50,str);
},ms);
}
};

打印(0,ms,str)设置超时(anyFunc,0),给出时间0毫秒并不意味着它将在0毫秒后运行,这意味着它将在事件循环发生时尽快运行。我建议使用PromiseSure确保在设置超时完成之前打印出来,它不是blocking@Mick承诺根本不会改变异步JavaScript回调的本质。它们只是提供了一种更好的方法来处理这些回调。
setTimeout(callback,delay)
安排
callback
delay
过后运行。然后,
setTimeout
调用立即返回。这就是为什么你看到了你得到的结果。