我有一个关于 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,但我认为,这只是为了模拟中断。
感谢您提前提供的帮助。
最诚挚的问候 帕斯卡
最佳答案
TL:DR
Promise 和 async
函数不会将您的代码卸载到另一个线程。如果您想将长时间运行的进程移出主线程,请在浏览器上查看 web workers ,在 Node.js 上查看 child processes .
详细信息
Promises 和 async
函数(只是创建和使用 Promise 的语法)不会将您的处理移动到任何其他线程,它仍然发生在您启动进程的同一线程上。他们所做的唯一事情是确保异步调用then
和catch
回调。它们不会使您的代码异步(除了确保回调异步发生之外)。
因此,使用 setTimeout
的第一个 block 只是设置超时,返回 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 的第二个 block 会立即阻塞,因为 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;
}
直到长时间运行的代码完成之后,我们才看到 before SlowFunction 日志出现,因为浏览器永远没有机会重新绘制,我们的线程被占用了。
关于async
函数:async
函数中的代码开始是同步的,并且在第一个await
之前都是同步的code> (或其他构造,例如 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
注意before wait如何出现在after foo之前;它与对 foo
的调用同步。但是 after wait 直到稍后才会发生(因为 await Promise.resolve()
必须使其后面的代码异步发生;它是 then 的语法糖
,它 promise 不会同步调用其处理程序,即使 promise 已经解决)。
关于javascript - 是否需要setTimeout?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50532391/