setTimeout 是使用 javascript 执行异步函数的好解决方案吗?

IT技术 javascript jquery
2021-02-02 07:46:43

在网上搜索有关异步函数的信息,我发现很多文章使用 setTimeout 来完成这项工作:

window.setTimeout(function() {
   console.log("second");
}, 0);
console.log("first");

输出:

first
second

这行得通,但这是最佳实践吗?

3个回答

setTimeout(function(){...}, 0)一旦当前调用堆栈完成执行,只需将代码排队即可运行。对某些事情很有用

所以是的,它是异步的,因为它打破了同步流程,但它实际上不会并发/在单独的线程上执行。如果您的目标是后台处理,请查看webworkers还有一种方法可以使用 iframe 进行后台处理。

更新

为了进一步澄清,并发/背景和异步之间存在差异。当代码是异步的时,仅仅意味着它不是按顺序执行的。考虑:

var foo='poo';
setTimeout(function() {
  foo='bar'
}, 100);
console.log(foo);

由于代码未按顺序执行,因此将警告值“poo”。'bar' 值是异步分配的。如果您需要提醒foo异步赋值发生的时间,请使用回调:

/* contrived example alert */
var foo = 'poo';

function setFoo(callback) {
  setTimeout(function() {
    foo = 'bar';
    callback();
  }, 100);
};
setFoo(function() {
  console.log(foo);
});

所以是的,上面发生了一些异步性,但这一切都发生在一个线程中,因此没有性能优势。

当一个操作需要很长时间时,最好在后台进行。在大多数语言中,这是通过在新线程或进程上执行操作来完成的。在(浏览器)javascript 中,我们无法创建新线程,但可以使用 webworkers 或 iframe。由于这段在后台运行的代码打破了事物的顺序流,因此它是异步的。

TLDR:所有后台/并发代码都是异步发生的,但并非所有异步代码都是并发发生的。

另请参阅用外行的术语理解异步代码

默认情况下,JavaScript 在遇到异步函数时是异步的,它会将该函数排入队列以备后用。但是,如果您想要暂停 js,则可以使用 promises 案例 1:输出 hello(不会等待 setTimeout) https://jsfiddle.net/shashankgpt270/h0vr53qy/

//async 
function myFunction() {
let result1='hello'
//promise =new Promise((resolve,reject)=>{
setTimeout(function(){ 
resolve("done");
result1="done1";
}, 3000);
//});
 //result = await promise
 alert(result1);
}
myFunction();

情况 2:输出 done1(将等待 setTimeout) https://jsfiddle.net/shashankgpt270/1o79fudt/

async function myFunction() {
let result1='hello'
promise =new Promise((resolve,reject)=>{
setTimeout(function(){ 
resolve("done");
result1="done1";
}, 3000);
});
 result = await promise
 alert(result1);
}
myFunction();
如果您已经在编写异步程序,那么有一种非常方便的方法可以使它具有可读性function asleep(delay) { return new Promise(resolve => setTimeout(resolve, delay)); }-那么您可以轻松地await asleep(2000);在任何async函数中内联
2021-04-04 07:46:43
var foo = 'poo';
setTimeout(function() {foo = 'bar'}, 100);
alert(foo);

对@tybro0103 的回答的一个小更正,在执行 'alert(foo)' 期间,值 'poo' 不会改变,因为代码不是按顺序执行的。'bar' 值是异步分配的,它只会在 100 毫秒后执行,届时将执行警报。

在执行行 alert(foo) 期间foo的值保持不变并且会及时更改。检查@vishal-lia 评论。

* 你的意思是值 'bar' 不会被提醒,因为alert已经触发foo
2021-03-25 07:46:43
我将 setTimeout(..) 中的数值更改为 0。结果它仍然打印“poo”,即该值没有改变。你能解释一下为什么吗?
2021-04-06 07:46:43
当您说“foo 的值保持不变”时。你实际上让人们感到困惑。foo 肯定会更改为 'bar' 但 100 毫秒后,如果您记录 'foo',它仍会打印 'poo',因为在 100 毫秒后调用了“function() {foo = 'bar'}”。您可以在浏览器控制台中验证以检查值的变化。
2021-04-06 07:46:43
@VaisakhRajagopal 没问题,所以一旦当前堆栈完成加上指定的毫秒数(而不是仅指定的毫秒数), setTimeout 函数就会运行。谢谢!
2021-04-11 07:46:43
是的,您可以通过在控制台上执行相同的操作来轻松验证它。
2021-04-14 07:46:43