理解 JavaScript 中的 Iterator、Generator、Promise 与 async/await

Iterator 迭代器

在 JavaScript 中,数组、字符串、Map、Set 等都是可迭代对象。但如果你想要遍历一个自定义的数据结构(比如链表、树),没有内置遍历机制该怎么办?

这就是 迭代器模式 出现的原因 ------ 提供统一的访问接口,让不同的数据结构都可以被 for...of 遍历。

工作原理

  1. 创建一个指针对象,指向当前数据结构的起始位置
  2. 第一次调用next()方法,指针自动指向数据结构的第一个成员
  3. 每次调用next(),指针就往后移动
  4. 每次next(),返回一个对象{value,done}
    • value:当前成员值
    • done:是否遍历完成
js 复制代码
const arr = [10, 20, 30];
const it = arr[Symbol.iterator]();

console.log(it.next()); // { value: 10, done: false }
console.log(it.next()); // { value: 20, done: false }
console.log(it.next()); // { value: 30, done: false }
console.log(it.next()); // { value: undefined, done: true }

本质

  • 把遍历逻辑抽象成一个接口
  • 内部维护当前位置,每次调用next()更新状态

手写迭代器

js 复制代码
function createIterator(arr) {
  let index = 0;
  return {
    next() {
      if (index < arr.length) {
        return { value: arr[index++], done: false };
      } else {
        return { value: undefined, done: true };
      }
    }
  };
}

const it = createIterator([1, 2, 3]);
console.log(it.next()); // { value: 1, done: false }
console.log(it.next()); // { value: 2, done: false }
console.log(it.next()); // { value: 3, done: false }
console.log(it.next()); // { value: undefined, done: true }

Generator 生成器

Generator 是 特殊的函数 ,用 function* 定义,执行时可以被"暂停"和"恢复"。

工作原理

  • 调用function*定义的函数,不会立即执行,而是返回一个迭代器对象
  • 调用next(),函数执行到yeild暂停,并返回对应的值
  • 下次执行next(),会接着上次暂停处继续
  • 可以通过next(value)把值传回函数内部
  • 直到函数结束,返回{value:undefined,done:true}
js 复制代码
function* gen() {
  yield 1;
  yield 2;
  yield 3;
}
const it = gen();

console.log(it.next()); // { value: 1, done: false }
console.log(it.next()); // { value: 2, done: false }
console.log(it.next()); // { value: 3, done: false }
console.log(it.next()); // { value: undefined, done: true }

本质

  • 是迭代协议的语法糖
  • 内部是一个状态机,能在不同状态间来回切换
  • 支持协程风格的异步编程(后来async/await取代了它)

Promise

为什么需要Promise?

  • 解决回调地狱
  • 提供统一的异步 API (then/catch/finally)
  • 可链式调用,错误统一处理

工作原理

  • 创建时立即执行 executor(resolve, reject)
  • 内部维护三种状态
    • pending
    • fulfilled
    • rejected
  • 状态发生变化就不可逆
  • 调用then/catch方法,回调会放入微任务队列,在事件循环末端执行
js 复制代码
const p = new Promise((resolve, reject) => {
  setTimeout(() => resolve("ok"), 1000);
});

p.then(res => console.log(res)); // 1秒后打印 "ok"

本质

  • 状态机 + 异步任务调度器

  • 把异步结果抽象成一个"可组合的值";

  • 避免了传统回调地狱。

async/await

为什么需要async/await?

  • Promise 链虽然解决了回调地狱,但可读性仍差
  • async/await 可以写出 同步风格异步代码
  • 错误处理更简单(try/catch)

工作原理

  • async function调用后,始终返回一个Promise
  • 执行遇到await时
    • 表达式立即执行
    • 如果是普通值,转成 Promise.resolve(value)
    • 如果是promise,暂停函数执行,等待结果
  • 等 Promise 完成后,恢复执行,并把结果返回给 await 表达式
  • 如果Promise失败,抛出错误,可以使用try...catch捕获
js 复制代码
async function getData() {
  const res = await new Promise(resolve => setTimeout(() => resolve("ok"), 1000));
  console.log(res); // "ok"
}
getData();

本质

  • Generator + Promise 的语法糖
  • Babel 转译 async/await → Generator
  • 让异步代码看起来像同步,更易读易维护

babel转译原理

js 复制代码
async function fetchData() {
  const a = await getA();
  const b = await getB(a);
  return b;
}

// 转译等价于
function fetchData() {
  return _asyncToGenerator(function* () {
    const a = yield getA();
    const b = yield getB(a);
    return b;
  })();
}

function _asyncToGenerator(genFn) {
  return function() {
    const gen = genFn.apply(this, arguments);
    return new Promise((resolve, reject) => {
      function step(key, arg) {
        let info;
        try { info = gen[key](arg); } 
        catch (err) { return reject(err); }
        if (info.done) resolve(info.value);
        else Promise.resolve(info.value)
          .then(val => step("next", val), err => step("throw", err));
      }
      step("next");
    });
  }
}
相关推荐
云枫晖1 分钟前
手写Promise-静态方法reoslve和reject
前端·javascript
浮幻云月5 分钟前
让 Vue 动画如德芙般丝滑!这个 FLIP 动画组件绝了!
前端·javascript
吃饺子不吃馅13 分钟前
揭秘 X6 核心概念:Graph、Node、Edge 与 View
前端·javascript·svg
qwy71522925816315 分钟前
Vue中的Provide/Inject如何实现动态数据
前端·javascript·vue.js
艾小码15 分钟前
告别重复代码!React自定义Hook让逻辑复用如此简单
前端·javascript·react.js
yoyoma17 分钟前
react-infinite-scroll-component 使用注意事项
前端
快乐是一切19 分钟前
PDF文件的交叉引用表(xref)与 trailer
前端
emma羊羊1 小时前
【CSRF】防御
前端·网络安全·csrf
Paddy哥1 小时前
html调起exe程序
前端·html
菠菠萝宝1 小时前
【Java八股文】12-分布式面试篇
java·分布式·zookeeper·面试·seata·redisson