这段JavaScript示例代码中async/await的具体运行机制是怎样的?
async/await 异步执行机制答疑
示例代码回顾
async function myFetch() { let response = await fetch('coffee.jpg'); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } let myBlob = await response.blob(); let objectURL = URL.createObjectURL(myBlob); let image = document.createElement('img'); image.src = objectURL; document.body.appendChild(image); } myFetch() .catch(e => { console.log('There has been a problem with your fetch operation: ' + e.message); });
完整执行流程
- 主线程同步执行代码,先完成
myFetch函数定义,随后调用myFetch()进入函数内部执行 - 函数内同步调用
fetch('coffee.jpg'):fetch是浏览器提供的网络API,调用后会将实际网络请求交给浏览器的网络线程处理,同步返回一个pending状态的Promise - 遇到第一个
await关键字:- 暂停
myFetch函数内部后续代码的执行 - 直接将
myFetch的返回值设为一个pending状态的Promise,退出函数执行,主线程继续执行后续的myFetch().catch(...)回调绑定,以及其他同步任务(比如页面渲染、用户交互事件处理等)
- 暂停
- 浏览器网络线程处理完请求后,会将fetch返回的Promise状态改为fulfilled(请求成功)或rejected(请求失败),对应的状态变更回调会被推入微任务队列
- 主线程空闲时,会优先从微任务队列取任务执行,此时恢复
myFetch的执行,将请求结果赋值给response变量 - 执行
response.ok判断:如果结果为false,直接抛出错误,myFetch返回的Promise状态变为rejected,触发后续绑定的catch回调 - 判断通过后,调用
response.blob(),该操作同样由浏览器底层线程处理,返回Promise,遇到第二个await,再次暂停myFetch执行,主线程继续处理其他任务 - blob解析完成后,Promise状态变更,回调进入微任务队列,主线程空闲时恢复
myFetch执行,将解析结果赋值给myBlob - 后续的
URL.createObjectURL、创建img元素、插入DOM均为同步操作,全部执行完成后,myFetch返回的Promise状态变为fulfilled - 整个流程中任何一步抛出的错误,都会被
myFetch返回的Promise捕获,触发catch回调
常见误区澄清
1. async函数是否会被分配到其他线程执行?
不会。所有JavaScript逻辑都在主线程执行,async/await本质是Promise的语法糖,完全基于JS的事件循环机制实现,不会创建新的JS执行线程。你感知到的不阻塞,是因为真正耗时的操作(网络请求、二进制数据解析)是运行环境(浏览器/Node.js)的非JS线程处理的,JS主线程只是在等待结果的时间段让出执行权去处理其他任务,并没有被占用。
2. await会暂停代码执行,为什么不会阻塞主线程?
await暂停的仅为当前async函数内部的后续代码,不是整个主线程。遇到await后,当前async函数会立刻让出主线程的执行权,主线程可以继续执行外层同步代码、响应用户操作、渲染页面,完全不会被阻塞。等异步操作有结果后,再通过事件循环机制,将async函数后续代码放到主线程空闲时执行,本质还是异步逻辑。
你可以做个简单测试:在myFetch().catch(...)后面加一行console.log('主线程同步任务'),这行日志会早于await后面的所有代码执行,就能直观验证await不会阻塞主线程。
内容的提问来源于stack exchange,提问作者Jigau Rafael
相关产品推荐
相关产品推荐

