是否需要setTimeout?(Is setTimeout required?)

编程入门 行业动态 更新时间:2024-10-28 15:32:45
是否需要setTimeout?(Is setTimeout required?)

我有一个async,await和setTimeout()的问题。 我想,我使用异步函数来处理慢进程。 所以我尝试了一个大循环。 在我的计算机上,运行以下代码需要几秒钟:

function slowFunction() { return new Promise(resolve => { setTimeout(() => { for (let i = 0; i < 4000000000; i++) {}; resolve('Ready at ' + new Date().toLocaleTimeString('de')); }, 0); }); }; console.log('Start: ' + new Date().toLocaleTimeString('de')); (async () => { console.log('Call slow function.'); console.log(await slowFunction()); })(); console.log('There is no need to wait for the slow function: ' + new Date().toLocaleTimeString('de'));

输出是:

Start: 16:39:20 Call slow function. There is no need to wait for the slow function: 16:39:20 Ready at 16:39:23

现在问题是:下一个代码有什么区别:

function slowFunction() { return new Promise(resolve => { for (let i = 0; i < 4000000000; i++) {}; resolve('Ready at ' + new Date().toLocaleTimeString('de')); }); }; console.log('Start: ' + new Date().toLocaleTimeString('de')); (async () => { console.log('Call slow function.'); console.log(await slowFunction()); })(); console.log('There is no need to wait for the slow function: ' + new Date().toLocaleTimeString('de'));

输出是:

Start: 16:39:20 Call slow function. There is no need to wait for the slow function: 16:39:23 Ready at 16:39:23

通过第一个例子,它看起来像异步。 通过第二个例子,函数等待循环结束。

我是否必须使用setTimeout或者代码中是否有错误或者我错了? 在这两种情况下,解决方案都是大循环的背后。

async和await的大多数例子都使用了setTimeout,但我想,这只是为了模拟一个中断。

感谢您的帮助。

最好迎接Pascal

I have a question to async, await and setTimeout(). I thought, I use asynchron functions for slow processes. So I tried it with a large loop. On my Computer, it needs few seconds to run the following code:

function slowFunction() { return new Promise(resolve => { setTimeout(() => { for (let i = 0; i < 4000000000; i++) {}; resolve('Ready at ' + new Date().toLocaleTimeString('de')); }, 0); }); }; console.log('Start: ' + new Date().toLocaleTimeString('de')); (async () => { console.log('Call slow function.'); console.log(await slowFunction()); })(); console.log('There is no need to wait for the slow function: ' + new Date().toLocaleTimeString('de'));

The output is:

Start: 16:39:20 Call slow function. There is no need to wait for the slow function: 16:39:20 Ready at 16:39:23

And now the question: What is the difference to the next code:

function slowFunction() { return new Promise(resolve => { for (let i = 0; i < 4000000000; i++) {}; resolve('Ready at ' + new Date().toLocaleTimeString('de')); }); }; console.log('Start: ' + new Date().toLocaleTimeString('de')); (async () => { console.log('Call slow function.'); console.log(await slowFunction()); })(); console.log('There is no need to wait for the slow function: ' + new Date().toLocaleTimeString('de'));

The output is:

Start: 16:39:20 Call slow function. There is no need to wait for the slow function: 16:39:23 Ready at 16:39:23

By the first example, it looks like asynchron. By the second example, the function wait for the end of loop.

Do I have to use setTimeout or do I have an error in the code or am I getting it wrong? I both cases, the resolve statment is behind the large loop.

The most examples for async and await used setTimeout, but I think, it's just to simulate a break.

Thanks for your help in advance.

Best greets Pascal

最满意答案

TL:DR

Promise和async函数不会将代码卸载到另一个线程。 如果要将长时间运行的进程从主线程移开,则在浏览器上查看Web工作者 ,在Node.js上查看子进程 。

细节

Promise和async函数(它们只是创建和使用promises的语法)不会将您的处理移动到任何其他线程,它仍然发生在您启动该进程的同一个线程上。 他们唯一要做的就是确保then异步调用catch回调。 它们不会使您的代码异步(除了那一件事,确保回调异步发生)。

因此,使用setTimeout的第一个块只设置超时,返回一个promise,然后当超时到期时,它会阻止主线程,同时执行慢速运行的进程。 这只是在阻塞发生一点点时改变,它不会改变阻塞的事实。

您可以在此处查看该效果,注意计数器在长时间运行的进程发生时如何暂停:

function slowFunction() {
  return new Promise(resolve => {
    setTimeout(() => {
      const stop = Date.now() + 2000;
      while (Date.now() < stop) {
        // busy wait (obviously, never really do this)
      }
    }, 1000);
  });
};

console.log("before slowFunction");
slowFunction()
  .then(() => {
    console.log("then handler on slowFunction's promise");
  })
  .catch(console.error);
console.log("after slowFunction");

let counter = 0;
const timer = setInterval(() => {
  console.log(++counter);
}, 100);
setTimeout(() => {
  clearInterval(timer);
  console.log("done");
}, 3000); 
  
.as-console-wrapper {
  max-height: 100% !important;
} 
  
 

你的第二个不使用setTimeout块只是立即阻塞,因为promise执行器函数(传递new Promise的函数)立即同步运行,而你没有做任何事情来使它异步。

你可以在这里看到; 柜台立即暂停,不迟于:

function slowFunction() {
  return new Promise(resolve => {
    const stop = Date.now() + 2000;
    while (Date.now() < stop) {
      // busy wait (obviously, never really do this)
    }
  });
};

console.log("before slowFunction");
slowFunction()
  .then(() => {
    console.log("then handler on slowFunction's promise");
  })
  .catch(console.error);
console.log("after slowFunction");

let counter = 0;
const timer = setInterval(() => {
  console.log(++counter);
}, 100);
setTimeout(() => {
  clearInterval(timer);
  console.log("done");
}, 3000); 
  
.as-console-wrapper {
  max-height: 100% !important;
} 
  
 

我们甚至没有看到之前的慢函数日志出现,直到长时间运行的代码完成,因为浏览器永远没有机会重新绘制,我们让线程陷入困境。

关于async函数: async函数中的代码以async 开始 ,并且在第一个await之前是同步的(或其他构造,例如setTimeout ,用于调度以后执行的事物)。 只有那之后的代码是异步的(因为它必须等待)。

这是一个证明:

async function foo() {
  console.log("before await");
  await Promise.resolve();
  console.log("after await");
}

console.log("before foo");
foo()
  .then(() => {
    console.log("then handler on foo's promise");
  })
  .catch(console.error);
console.log("after foo"); 
  
 

这是输出:

before foo before await after foo after await then handler on foo's promise

请注意在foo 之前await之前是如何发生的; 它与foo的调用同步。 但是之后等待直到稍后才发生(因为await Promise.resolve()必须使其后面的代码异步发生;它是then的语法糖,它承诺即使承诺已经解决也不会同步调用它的处理程序) 。

TL:DR

Promises and async functions don't offload your code to another thread. If you want to move that long-running process off the main thread, on browsers look at web workers, and on Node.js look at child processes.

Details

Promises and async functions (which are just a syntax for creating and consuming promises) don't move your processing to any other thread, it still happens on the same thread you start the process on. The only thing they do is ensure that then and catch callbacks are called asynchronously. They don't make your code asynchronous (other than that one thing, ensuring the callbacks happen asynchronously).

So your first block using setTimeout just sets a timeout, returns a promise, and then when the timeout expires it blocks the main thread while your slow-running process executes. This just changes when the blocking happens a little bit, it doesn't change the fact of the blocking.

You can see that effect here, notice how the counter pauses when the long-running process occurs:

function slowFunction() {
  return new Promise(resolve => {
    setTimeout(() => {
      const stop = Date.now() + 2000;
      while (Date.now() < stop) {
        // busy wait (obviously, never really do this)
      }
    }, 1000);
  });
};

console.log("before slowFunction");
slowFunction()
  .then(() => {
    console.log("then handler on slowFunction's promise");
  })
  .catch(console.error);
console.log("after slowFunction");

let counter = 0;
const timer = setInterval(() => {
  console.log(++counter);
}, 100);
setTimeout(() => {
  clearInterval(timer);
  console.log("done");
}, 3000); 
  
.as-console-wrapper {
  max-height: 100% !important;
} 
  
 

Your second block not using setTimeout just blocks right away, because the promise executor function (the function you pass new Promise) runs immediately and synchronously, and you're not doing anything to make it asynchronous.

You can see that here; the counter pauses right away, not later:

function slowFunction() {
  return new Promise(resolve => {
    const stop = Date.now() + 2000;
    while (Date.now() < stop) {
      // busy wait (obviously, never really do this)
    }
  });
};

console.log("before slowFunction");
slowFunction()
  .then(() => {
    console.log("then handler on slowFunction's promise");
  })
  .catch(console.error);
console.log("after slowFunction");

let counter = 0;
const timer = setInterval(() => {
  console.log(++counter);
}, 100);
setTimeout(() => {
  clearInterval(timer);
  console.log("done");
}, 3000); 
  
.as-console-wrapper {
  max-height: 100% !important;
} 
  
 

We don't even see the before slowFunction log appear until after the long-running code has finished, because the browser never got a chance to repaint, we had the thread hogged.

Regarding async functions: The code in an async function starts out synchronous, and is synchronous until the first await (or other construct, such as setTimeout, that schedules things to execute later). Only the code after that is asynchronous (because it had to wait).

Here's an example demonstrating that:

async function foo() {
  console.log("before await");
  await Promise.resolve();
  console.log("after await");
}

console.log("before foo");
foo()
  .then(() => {
    console.log("then handler on foo's promise");
  })
  .catch(console.error);
console.log("after foo"); 
  
 

Here's the output of that:

before foo before await after foo after await then handler on foo's promise

Notice how before await occurs before after foo; it's synchronous with the call to foo. But then after await doesn't occur until later (because await Promise.resolve() has to make the code following it occur asynchronously; it's syntactic sugar for then, which promises not to call its handler synchronously even if the promise is already resolved).

更多推荐

本文发布于:2023-07-14 23:33:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1108313.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:setTimeout   required

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!