JavaScript自定义async异步函数未实现预期异步行为如何解决
问题出现的原因
async函数在遇到第一个await关键字之前,所有代码都是同步执行的。你提供的代码中myFunc内部没有任何await语句,因此整个函数体(包括超长for循环、console.log('After for loop'))都会在调用myFunc()的时候同步阻塞执行,不会被提交到事件循环队列等待后续处理。- JavaScript主线程是单线程运行的,同步代码执行优先级永远高于异步任务,你没有做任何异步挂起操作的情况下,for循环会直接阻塞主线程,直到循环跑完才会执行后面的
console.log('end'),因此输出顺序不符合预期。
解决方案
方案1:添加await让出主线程,将后续逻辑提交到微任务队列
在async函数最开头添加一行await语句,即可让await之后的所有逻辑被挂起,放到微任务队列,等待当前所有同步代码执行完成后再运行,修改后代码如下:
console.log('Start'); const myFunc = async () => { // 只要出现await,后续逻辑就会进入异步队列等待执行 await Promise.resolve(); for(let i=0; i<10000000000000; i++){} console.log('After for loop'); } myFunc(); console.log('end');
运行后输出顺序就符合预期:Start → end → After for loop。
注意:该方案只是把重计算逻辑延后执行,计算过程仍然会占用主线程,执行期间页面交互、渲染都会被阻塞,仅适合轻量延后执行的场景。
方案2:使用Web Worker实现真后台计算
如果你的计算逻辑非常重,不想阻塞主线程的任何操作,应该使用Web Worker创建独立的后台线程运行计算逻辑,完全不占用主线程资源,示例逻辑如下:
- 新建
worker.js文件,存放计算逻辑:
// worker.js self.onmessage = () => { for(let i=0; i<10000000000000; i++){} self.postMessage('done') }
- 主线程代码:
console.log('Start'); const worker = new Worker('./worker.js'); worker.postMessage('start'); worker.onmessage = () => { console.log('After for loop'); } console.log('end');
该方案下重计算完全在独立线程运行,主线程全程不会被阻塞,也符合你期望的输出顺序。
内容的提问来源于stack exchange,提问作者Mayur Panchal
相关产品推荐
相关产品推荐

