logo

从Promise到async/await:手写实现异步编程核心机制全解析

作者:很菜不狗2025.09.19 12:47浏览量:0

简介:本文深入解析异步编程核心机制,通过手写实现Promise全家桶、Generator及async/await,揭示其底层原理与协作关系。从基础Promise到高级语法,逐步构建完整的异步控制体系,帮助开发者彻底掌握JavaScript异步编程精髓。

一、Promise核心机制手写实现

1.1 Promise基础结构

Promise本质是一个具有状态的特殊对象,包含三种状态转换逻辑:

  1. class MyPromise {
  2. constructor(executor) {
  3. this.state = 'pending'; // pending/fulfilled/rejected
  4. this.value = undefined;
  5. this.reason = undefined;
  6. this.onFulfilledCallbacks = [];
  7. this.onRejectedCallbacks = [];
  8. const resolve = (value) => {
  9. if (this.state === 'pending') {
  10. this.state = 'fulfilled';
  11. this.value = value;
  12. this.onFulfilledCallbacks.forEach(fn => fn());
  13. }
  14. };
  15. const reject = (reason) => {
  16. if (this.state === 'pending') {
  17. this.state = 'rejected';
  18. this.reason = reason;
  19. this.onRejectedCallbacks.forEach(fn => fn());
  20. }
  21. };
  22. try {
  23. executor(resolve, reject);
  24. } catch (err) {
  25. reject(err);
  26. }
  27. }
  28. }

关键设计点:

  • 状态机模型:严格限制状态单向转换
  • 异步回调队列:解决then方法调用时机问题
  • 错误捕获机制:通过try-catch统一处理执行器错误

1.2 then方法链式调用实现

  1. then(onFulfilled, onRejected) {
  2. // 参数默认值处理
  3. onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
  4. onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
  5. const promise2 = new MyPromise((resolve, reject) => {
  6. if (this.state === 'fulfilled') {
  7. setTimeout(() => {
  8. try {
  9. const x = onFulfilled(this.value);
  10. resolvePromise(promise2, x, resolve, reject);
  11. } catch (e) {
  12. reject(e);
  13. }
  14. }, 0);
  15. } else if (this.state === 'rejected') {
  16. setTimeout(() => {
  17. try {
  18. const x = onRejected(this.reason);
  19. resolvePromise(promise2, x, resolve, reject);
  20. } catch (e) {
  21. reject(e);
  22. }
  23. }, 0);
  24. } else if (this.state === 'pending') {
  25. this.onFulfilledCallbacks.push(() => {
  26. setTimeout(() => {
  27. try {
  28. const x = onFulfilled(this.value);
  29. resolvePromise(promise2, x, resolve, reject);
  30. } catch (e) {
  31. reject(e);
  32. }
  33. }, 0);
  34. });
  35. this.onRejectedCallbacks.push(() => {
  36. setTimeout(() => {
  37. try {
  38. const x = onRejected(this.reason);
  39. resolvePromise(promise2, x, resolve, reject);
  40. } catch (e) {
  41. reject(e);
  42. }
  43. }, 0);
  44. });
  45. }
  46. });
  47. return promise2;
  48. }

实现要点:

  • 微任务队列模拟:使用setTimeout模拟异步调度
  • 值穿透处理:非函数参数直接透传值
  • 返回值解析:通过resolvePromise处理thenable对象

1.3 静态方法实现

  1. // 全局resolve方法
  2. static resolve(value) {
  3. if (value instanceof MyPromise) {
  4. return value;
  5. }
  6. return new MyPromise(resolve => resolve(value));
  7. }
  8. // 全局reject方法
  9. static reject(reason) {
  10. return new MyPromise((_, reject) => reject(reason));
  11. }
  12. // 全局all方法
  13. static all(promises) {
  14. return new MyPromise((resolve, reject) => {
  15. const results = [];
  16. let count = 0;
  17. const processValue = (index, value) => {
  18. results[index] = value;
  19. count++;
  20. if (count === promises.length) {
  21. resolve(results);
  22. }
  23. };
  24. promises.forEach((promise, index) => {
  25. if (promise instanceof MyPromise) {
  26. promise.then(
  27. value => processValue(index, value),
  28. reason => reject(reason)
  29. );
  30. } else {
  31. processValue(index, promise);
  32. }
  33. });
  34. });
  35. }

二、Generator函数实现原理

2.1 生成器基础结构

  1. function* myGenerator() {
  2. yield 1;
  3. yield 2;
  4. return 3;
  5. }
  6. // 手写生成器迭代器
  7. class Generator {
  8. constructor(generatorFn) {
  9. this.generatorFn = generatorFn;
  10. this.context = {};
  11. this.step = null;
  12. this.init();
  13. }
  14. init() {
  15. this.step = this.generatorFn.call(this.context);
  16. }
  17. next(value) {
  18. const result = this.step.next(value);
  19. if (!result.done) {
  20. // 保存当前执行位置
  21. this.step = result.value;
  22. }
  23. return result;
  24. }
  25. [Symbol.iterator]() {
  26. return this;
  27. }
  28. }

核心机制:

  • 状态保存:通过闭包保存执行上下文
  • 迭代协议:实现next方法返回{value, done}对象
  • 协程模型:yield表达式暂停执行

2.2 自动执行器实现

  1. function co(generatorFn) {
  2. return new Promise((resolve, reject) => {
  3. const gen = generatorFn();
  4. function step(nextFn) {
  5. let result;
  6. try {
  7. result = nextFn();
  8. } catch (err) {
  9. return reject(err);
  10. }
  11. if (result.done) {
  12. return resolve(result.value);
  13. }
  14. Promise.resolve(result.value).then(
  15. value => step(() => gen.next(value)),
  16. reason => step(() => gen.throw(reason))
  17. );
  18. }
  19. step(() => gen.next());
  20. });
  21. }

执行流程:

  1. 初始化生成器
  2. 递归执行next/throw方法
  3. 自动处理Promise链式调用
  4. 最终结果透传

三、async/await编译原理

3.1 语法糖转换

async函数本质是Generator函数的语法糖,Babel转换示例:

  1. // 源码
  2. async function fetchData() {
  3. const res = await fetch('/api');
  4. return res.json();
  5. }
  6. // 转换后
  7. function fetchData() {
  8. return regeneratorRuntime.async(function fetchData$(_context) {
  9. while (1) {
  10. switch (_context.prev = _context.next) {
  11. case 0:
  12. _context.next = 2;
  13. return regeneratorRuntime.awrap(fetch('/api'));
  14. case 2:
  15. res = _context.sent;
  16. return _context.abrupt('return', res.json());
  17. case 4:
  18. case 'end':
  19. return _context.stop();
  20. }
  21. }
  22. }, null, this);
  23. }

关键转换点:

  • async函数转换为Generator函数
  • await表达式转换为yield表达式
  • 自动添加执行器逻辑

3.2 运行时支持

regeneratorRuntime核心方法:

  1. const regeneratorRuntime = {
  2. async(generatorFn, receiver, thisArg) {
  3. return new Promise((resolve, reject) => {
  4. const generator = generatorFn.apply(thisArg, [receiver]);
  5. function handle(result) {
  6. if (result.done) {
  7. resolve(result.value);
  8. } else {
  9. Promise.resolve(result.value).then(
  10. value => handle(generator.next(value)),
  11. reason => {
  12. try {
  13. handle(generator.throw(reason));
  14. } catch (err) {
  15. reject(err);
  16. }
  17. }
  18. );
  19. }
  20. }
  21. handle(generator.next());
  22. });
  23. },
  24. awrap(promise) {
  25. return { __await: promise };
  26. }
  27. };

四、异步编程最佳实践

4.1 Promise组合技巧

  1. // 并发控制
  2. function limitConcurrency(promises, limit) {
  3. return new Promise((resolve, reject) => {
  4. const results = [];
  5. let index = 0;
  6. let resolving = 0;
  7. function execute() {
  8. if (index >= promises.length && resolving === 0) {
  9. return resolve(results);
  10. }
  11. while (resolving < limit && index < promises.length) {
  12. resolving++;
  13. const currentIndex = index++;
  14. Promise.resolve(promises[currentIndex]())
  15. .then(result => {
  16. results[currentIndex] = result;
  17. })
  18. .catch(reject)
  19. .finally(() => {
  20. resolving--;
  21. execute();
  22. });
  23. }
  24. }
  25. execute();
  26. });
  27. }

4.2 错误处理模式

  1. // 集中式错误处理
  2. async function safeExecute(asyncFn) {
  3. try {
  4. return { success: true, data: await asyncFn() };
  5. } catch (error) {
  6. return { success: false, error };
  7. }
  8. }
  9. // 链式错误恢复
  10. function retry(fn, times) {
  11. return new Promise((resolve, reject) => {
  12. function attempt() {
  13. Promise.resolve(fn())
  14. .then(resolve)
  15. .catch((err) => {
  16. if (times-- <= 0) {
  17. reject(err);
  18. } else {
  19. attempt();
  20. }
  21. });
  22. }
  23. attempt();
  24. });
  25. }

4.3 性能优化建议

  1. 避免Promise嵌套:使用扁平化链式调用
  2. 合理使用缓存:对重复请求结果进行缓存
  3. 资源释放:及时取消不再需要的请求
  4. 批量处理:合并多个小请求为大请求

五、完整实现示例

  1. // 完整Promise实现
  2. class CompletePromise {
  3. // ...前文Promise实现代码...
  4. }
  5. // 添加catch方法
  6. CompletePromise.prototype.catch = function(onRejected) {
  7. return this.then(null, onRejected);
  8. };
  9. // 添加finally方法
  10. CompletePromise.prototype.finally = function(callback) {
  11. return this.then(
  12. value => CompletePromise.resolve(callback()).then(() => value),
  13. reason => CompletePromise.resolve(callback()).then(() => { throw reason })
  14. );
  15. };
  16. // 测试用例
  17. const promise = new CompletePromise((resolve) => {
  18. setTimeout(() => resolve('Success'), 1000);
  19. });
  20. promise
  21. .then(res => {
  22. console.log(res); // Success
  23. return new CompletePromise(resolve => resolve('Nested'));
  24. })
  25. .then(res => console.log(res)) // Nested
  26. .catch(err => console.error(err))
  27. .finally(() => console.log('Completed'));

六、总结与展望

  1. 实现要点总结

    • Promise核心是状态机+异步回调队列
    • Generator通过yield实现协程控制
    • async/await是Generator的语法糖封装
  2. 应用场景选择

    • 简单异步:Promise直接使用
    • 复杂流程:Generator+co组合
    • 现代开发:优先使用async/await
  3. 未来演进方向

    • 结合Observables处理流式数据
    • 与Web Workers的异步集成
    • 更精细的并发控制机制

通过手写实现这些核心机制,开发者不仅能深入理解JavaScript异步编程原理,还能在实际开发中更灵活地运用这些技术,编写出更健壮、高效的异步代码。

相关文章推荐

发表评论