【问题标题】:Is setTimeout a good solution to do async functions with javascript?setTimeout 是使用 javascript 执行异步函数的好方法吗?
【发布时间】:2013-11-06 17:54:36
【问题描述】:

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

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

输出:

first
second

这可行,但是否是最佳做法?

【问题讨论】:

  • 这当然是最简单的技术。但是,如果您实际上是在尝试在单独的线程中运行异步任务,web workers 会更有效。 (HTML 5)
  • @minitech:这正是我的观点(setTimeout 在单线程中运行,而网络工作者则没有)。它们有不同的用途,当网络工作者确实是他们正在寻找的东西时,人们经常使用setTimeout。在不了解 OP 试图完成的任务的更多细节的情况下,我不确定哪个最适合这种情况。
  • 练习?不要管那个。你的目标是什么?告诉我们,然后我们可以帮助您最好地实现它。
  • @FlightOdyssey:哦。我不太明白那里“更有效”的含义。 :P
  • 异步不会有更好的性能。你只是在拖延即将发生的事情。如果你的代码需要在写之前等待,那么当然,保留它。

标签: javascript jquery


【解决方案1】:

setTimeout(function(){...}, 0) 只是在当前调用堆栈完成执行后将要运行的代码排队。这可以是useful for some things

所以是的,它是异步的,因为它打破了同步流程,但它实际上并不会同时/在单独的线程上执行。如果您的目标是后台处理,请查看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:所有后台/并发代码异步发生,但并非所有异步代码都同时发生。

另见Understanding Asynchronous Code in Layman's terms

【讨论】:

    【解决方案2】:

    默认情况下,JavaScript 在遇到异步函数时是异步的,它会将该函数排队以备后用。 但是如果你想要一个暂停 js,你可以使用 Promise 案例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功能
    【解决方案3】:
    var foo = 'poo';
    setTimeout(function() {foo = 'bar'}, 100);
    alert(foo);
    

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

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

    【讨论】:

    • * 你的意思是值'bar'不会被提醒,因为alert已经触发foo
    • 是的,正确,您可以通过在控制台上执行相同的操作轻松验证它。
    • 我将 setTimeout(..) 中的数值更改为 0。事实证明它仍然打印“便便”,即该值没有改变。你能解释一下原因吗?
    • @VaisakhRajagopal 好的,所以一旦当前堆栈完成加上指定的毫秒数(而不是指定的毫秒数),setTimeout 函数就会运行。谢谢!
    • 当您说“foo 的值保持不变”时。你实际上是在混淆人们。 foo 肯定会更改为 'bar' 但 100 毫秒后,如果您记录 'foo' 它仍会打印 'poo' 因为在 100 毫秒后调用了“function() {foo = 'bar'}”。您可以在浏览器控制台中验证以检查值的变化。
    猜你喜欢
    • 2021-06-29
    • 1970-01-01
    • 2022-01-21
    • 2019-03-04
    • 1970-01-01
    • 2017-06-05
    • 1970-01-01
    • 1970-01-01
    • 2019-12-17
    相关资源
    最近更新 更多