ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

210、【Agent】【OpenCode】JS 语法:async、Promise 与 await 的关系

210、【Agent】【OpenCode】JS 语法:async、Promise 与 await 的关系 【声明】本博客所有内容均为个人业余时间创作所述技术案例均来自公开开源项目如GithubApache基金会不涉及任何企业机密或未公开技术如有侵权请联系删除标题210、【Agent】【OpenCode】JS 语法async、Promise 与 await 的关系背景上篇 blog【Agent】【OpenCode】TUI 内部tui() 的生命周期 Promise拆了tui()的生命周期骨架render非阻塞所以函数返回一个退出才 resolve的 Promise 作为信号注释原话 prevent immediate exitonExitunguard resolve是唯一切入点被 ExitProvider 与 ErrorComponent 共用thread.ts 用await tui()挂起、退出后走双层 finally 收尾还点了async executor 反模式。209 一路在讲Promise/resolve/await/async怎么配合却没有系统地讲这四个词到底什么关系——本篇作为JS 语法系列的一篇把它们的底层关系讲透209 的tui()正好当现实案例OpenCode一句话先立骨架Promise是异步结果的容器resolve是生产者的发令枪await是消费者的取件口async是把函数自动包装成 Promise的糖。下面逐个展开。Promise一个将来才有值的容器Promise 不是值本身而是一个状态容器pending进行中 ├─ resolve(value) → fulfilled成功持有 value └─ reject(err) → rejected失败持有 err一旦从 pending 落定就不可再变——这也是resolve 只有第一次生效的原因。一个常见误解是new Promise就异步了其实executor 是同步执行的异步发生在消费侧newPromise((r){console.log(1)// 同步执行r()console.log(2)// 还是同步})// 立即打印 1、2r() 只负责标记落定真正的异步是.then/await的回调被排进微任务队列、等当前任务栈清空后才执行——Promise 包装的是将来才给结果不是现在不干活。resolve/reject生产者手动发令new Promise((resolve, reject) {...})的 executor 里resolve/reject是手动控制的开关——决定这个 Promise 何时、以什么结果落定functionwait(ms){returnnewPromise((resolve){setTimeout(()resolve(timeout!),ms)// 定时器到点才发令})}这个 Promise没有任何自动完成路径完全靠 resolve 发令。IO 完成、定时器到点、用户动作触发如 209 篇 onExit 里手动 resolve——都只是什么时候调 resolve的时机选择。reject 对应失败路径fulfilled/rejected 统称 settled已落定。await消费者的取件口await promise的语义挂起当前函数等这个 Promise 落定落定后恢复执行——fulfilled 则整个表达式等于 valuerejected 则原地抛出错误。// 写法 Aawait压平成顺序式像同步constvawaitwait(1000)// 写法 Bthen底层的回调式wait(1000).then((v){/* 这里才有 v */})await只是把.then的嵌套回调压平成顺序式——语法糖不是新机制。两者等价区别只在可读性回调嵌套深了会向右生长回调地狱await让异步流程读起来像同步。async自动包装器async function做两件事返回值自动包成 Promisereturn 42等价于return Promise.resolve(42)函数内throw等价于返回一个 rejected Promise函数内可用 await因为返回值本来就是 Promise 环境asyncfunctionf(){return42}// 调用得到 Promise42asyncfunctiong(){thrownewError()}// 调用得到 rejected Promise所以async与await是一对async 负责包装成 Promiseawait 负责消费 Promise。注意方向——async 不强制用 await但 await必须在 async 里因为普通函数没有挂起等落定的返回值环境。四个词串成一张图生产者 消费者 resolve(value) ──发令──► Promise ◄──挂起── await promise reject(err) ──发令──► (状态机) ◄──回调── .then / .catch ▲ │ async 自动包装 │ (函数 return → Promise) 待插入截图生产者 / Promise / 消费者 / async 包装的关系图角色是谁类比Promise异步结果的容器 / 状态机快递单号可查在途/已送达resolve / reject生产者的发令枪快递员签收那一刻await消费者的取件口收货人等快递、拿到包裹async自动包装器把任意函数变成可投递的快件套回 209 的 tui()209 篇那段代码正好把这四个词全用上returnnewPromisevoid(async(resolve){...constonExitasync(){unguard?.();resolve()}// 生产者发令render(...)// 非阻塞启动})new Promise(...)造一个退出信号容器resolve()onExit 里手动发令——TUI 一退出状态 pending → fulfilledawait tui()thread.ts消费者挂起等这个信号resolved 后继续走双层 finally 收尾asyncexecutor因为内部要先await getTerminalBackgroundColor()做准备只能把 executor 写成 async——代价就是 209 篇点破的反模式executor 抛错不会 reject 外层 Promise⚠️三个常见混淆点executor 是同步跑的new Promise不代表立刻异步执行异步在消费侧微任务调度别以为包个 Promise 就不阻塞了await 只在 async 里合法但 async 不一定要 awaitasync 首先是返回值变 Promiseawait 只是可选项resolve 是一次性的Promise 落定后再调 resolve/reject 全部无效想改结果只能另建 Promise一句话记忆Promise 是异步结果的容器pending→fulfilled/rejected落定不可变resolve/reject 是生产者的发令枪决定何时落定await 是消费者的取件口挂起等落定语法糖等价 thenasync 是自动包装器函数 return/throw 变成 fulfilled/rejected Promise。209 的 tui() 正是生产者 resolve 发令、消费者 await 挂起、async 自动包装的完整示例。OK本篇先到这里如有疑问欢迎评论区留言讨论祝各位功力大涨技术更上一层楼更多内容见下篇 blog
返回列表