logo

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

作者:问答酱2025.09.19 12:47浏览量:0

简介:本文通过手写实现Promise核心方法、Generator迭代器及async/await语法糖,深度解析JavaScript异步编程的底层原理,帮助开发者掌握异步控制流的本质逻辑。

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

异步编程是JavaScript开发的核心能力,而Promise、Generator和async/await构成了现代异步编程的三大支柱。本文将通过手写实现这些核心机制,深入解析其工作原理,帮助开发者建立完整的异步编程知识体系。

一、Promise核心机制手写实现

1.1 Promise基础结构

Promise本质是一个带有状态机的对象,包含三种状态:pending、fulfilled和rejected。手写实现需要重点处理状态变更的不可逆性。

  1. class MyPromise {
  2. constructor(executor) {
  3. this.state = 'pending'; // 初始状态
  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. }

1.2 then方法实现

then方法是Promise的核心,需要处理链式调用和异步回调:

  1. then(onFulfilled, onRejected) {
  2. // 参数默认值处理
  3. onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
  4. onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err; };
  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. }

1.3 解析Promise链式调用

关键在于resolvePromise函数的实现,它处理then方法返回值的各种情况:

  1. function resolvePromise(promise2, x, resolve, reject) {
  2. // 防止循环引用
  3. if (promise2 === x) {
  4. return reject(new TypeError('Chaining cycle detected for promise'));
  5. }
  6. let called = false;
  7. // 处理x为对象或函数的情况
  8. if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
  9. try {
  10. const then = x.then;
  11. if (typeof then === 'function') {
  12. then.call(
  13. x,
  14. y => {
  15. if (called) return;
  16. called = true;
  17. resolvePromise(promise2, y, resolve, reject);
  18. },
  19. r => {
  20. if (called) return;
  21. called = true;
  22. reject(r);
  23. }
  24. );
  25. } else {
  26. resolve(x);
  27. }
  28. } catch (e) {
  29. if (called) return;
  30. called = true;
  31. reject(e);
  32. }
  33. } else {
  34. resolve(x);
  35. }
  36. }

二、Generator函数实现原理

2.1 Generator基础实现

Generator的核心是状态机和迭代器协议:

  1. function* myGenerator() {
  2. yield 1;
  3. yield 2;
  4. return 3;
  5. }
  6. // 手写实现类似功能
  7. function createIterator(generatorFn) {
  8. const iterator = {
  9. next: function(value) {
  10. // 实际实现需要维护状态和上下文
  11. // 这里简化展示流程
  12. if (!this._init) {
  13. this._context = generatorFn.call(this);
  14. this._init = true;
  15. }
  16. const result = this._context.next(value);
  17. return {
  18. value: result.value,
  19. done: result.done
  20. };
  21. },
  22. _init: false,
  23. _context: null
  24. };
  25. return iterator;
  26. }

2.2 迭代器协议实现

完整的迭代器需要实现[Symbol.iterator]方法:

  1. function* countUpTo(max) {
  2. let count = 1;
  3. while (count <= max) {
  4. yield count++;
  5. }
  6. }
  7. // 转换为可迭代对象
  8. const iterable = {
  9. [Symbol.iterator]: function* () {
  10. yield* countUpTo(3);
  11. }
  12. };
  13. // 手写等效实现
  14. const manualIterable = {
  15. [Symbol.iterator]: function() {
  16. let count = 1;
  17. const max = 3;
  18. return {
  19. next: function() {
  20. if (count <= max) {
  21. return { value: count++, done: false };
  22. } else {
  23. return { done: true };
  24. }
  25. }
  26. };
  27. }
  28. };

三、async/await语法糖解析

3.1 async函数本质

async函数实际上是Generator函数的语法糖,编译器会将其转换为状态机:

  1. async function fetchData() {
  2. try {
  3. const res = await fetch('/api/data');
  4. const data = await res.json();
  5. return data;
  6. } catch (err) {
  7. console.error(err);
  8. }
  9. }
  10. // 等效的Generator实现
  11. function fetchDataGen() {
  12. return regeneratorRuntime.wrap(function fetchDataGen$(_context) {
  13. while (1) {
  14. switch (_context.prev = _context.next) {
  15. case 0:
  16. _context.prev = 0;
  17. _context.next = 3;
  18. return regeneratorRuntime.awrap(fetch('/api/data'));
  19. // ...其余实现
  20. }
  21. }
  22. }, fetchDataGen);
  23. }

3.2 手动实现async/await模式

通过Generator+Promise可以手动实现类似async/await的效果:

  1. function run(generatorFn) {
  2. const generator = generatorFn();
  3. function handle(result) {
  4. if (result.done) return Promise.resolve(result.value);
  5. return Promise.resolve(result.value).then(
  6. res => handle(generator.next(res)),
  7. err => handle(generator.throw(err))
  8. );
  9. }
  10. try {
  11. return handle(generator.next());
  12. } catch (err) {
  13. return Promise.reject(err);
  14. }
  15. }
  16. // 使用示例
  17. run(function* () {
  18. try {
  19. const res = yield fetch('/api/data');
  20. const data = yield res.json();
  21. console.log(data);
  22. } catch (err) {
  23. console.error(err);
  24. }
  25. });

四、实际应用与最佳实践

4.1 错误处理模式

  1. // Promise错误处理
  2. fetchData()
  3. .then(data => process(data))
  4. .catch(err => handleError(err));
  5. // async/await错误处理
  6. async function safeFetch() {
  7. try {
  8. const data = await fetchData();
  9. process(data);
  10. } catch (err) {
  11. handleError(err);
  12. }
  13. }

4.2 并行控制优化

  1. // Promise.all实现
  2. function myPromiseAll(promises) {
  3. return new Promise((resolve, reject) => {
  4. const results = [];
  5. let completed = 0;
  6. promises.forEach((promise, index) => {
  7. Promise.resolve(promise)
  8. .then(value => {
  9. results[index] = value;
  10. completed++;
  11. if (completed === promises.length) {
  12. resolve(results);
  13. }
  14. })
  15. .catch(reject);
  16. });
  17. });
  18. }
  19. // async/await中的并行优化
  20. async function fetchAll() {
  21. const [user, posts] = await Promise.all([
  22. fetchUser(),
  23. fetchPosts()
  24. ]);
  25. // ...
  26. }

五、性能优化与调试技巧

5.1 微任务与宏任务调度

  1. // 验证微任务优先级
  2. console.log('script start');
  3. setTimeout(() => {
  4. console.log('setTimeout');
  5. }, 0);
  6. new Promise((resolve) => {
  7. console.log('Promise executor');
  8. resolve();
  9. console.log('Promise executor after resolve');
  10. }).then(() => {
  11. console.log('Promise then');
  12. });
  13. console.log('script end');
  14. // 输出顺序:
  15. // script start
  16. // Promise executor
  17. // Promise executor after resolve
  18. // script end
  19. // Promise then
  20. // setTimeout

5.2 调试async/await

  1. // 使用生成器函数调试
  2. function* debugGen() {
  3. console.log('Before yield 1');
  4. yield 1;
  5. console.log('Between yield 1 and 2');
  6. yield 2;
  7. console.log('After yield 2');
  8. }
  9. const gen = debugGen();
  10. console.log(gen.next()); // 执行到第一个yield
  11. console.log(gen.next()); // 执行到第二个yield
  12. console.log(gen.next()); // 执行完毕

六、总结与展望

通过手写实现Promise、Generator和async/await的核心机制,我们深入理解了JavaScript异步编程的底层原理。这些实现不仅帮助我们更好地使用这些特性,也为解决复杂异步问题提供了理论基础。在实际开发中,建议:

  1. 优先使用async/await提高代码可读性
  2. 合理使用Promise.all等并行方法优化性能
  3. 注意错误处理的完整性
  4. 在需要精细控制的场景考虑使用Generator

随着JavaScript生态的发展,异步编程模式仍在不断演进,但掌握这些核心原理将使开发者能够更快适应新的异步编程范式。

相关文章推荐

发表评论