Event Loop 基础原理

JavaScript 的运行时基于单线程事件循环模型,核心分为调用栈(Call Stack)、微任务队列(Microtask Queue)和宏任务队列(Macrotask Queue)。调用栈执行同步代码,遇到异步任务时根据类型分发:

  • 宏任务setTimeoutsetInterval、I/O 操作
  • 微任务Promise.thenprocess.nextTickMutationObserver

执行顺序规则:

  1. 清空当前调用栈中的同步代码
  2. 检查微任务队列并执行所有微任务
  3. 取出一个宏任务执行
  4. 重复上述过程
console.log('同步1');
setTimeout(() => console.log('宏任务1'), 0);
Promise.resolve().then(() => console.log('微任务1'));
// 输出顺序: 同步1 → 微任务1 → 宏任务1

异步编程演进史

Callback 阶段

fs.readFile('file.txt', (err, data) => {
  if (err) throw err;
  console.log(data);
});

问题:回调地狱(Callback Hell),难以维护。

Promise 阶段

readFilePromise('file.txt')
  .then(data => console.log(data))
  .catch(err => console.error(err));

改进:链式调用,错误集中处理。

Generator + Co 阶段

function* gen() {
  const data = yield readFilePromise('file.txt');
  console.log(data);
}
co(gen);

特性:通过yield暂停执行,需要配合执行器使用。

Async/Await 阶段

async function main() {
  try {
    const data = await readFilePromise('file.txt');
    console.log(data);
  } catch (err) {
    console.error(err);
  }
}

本质:语法糖,将Generator+Promise的流程控制自动化。


Promise 核心实现

基础版Promise

class MyPromise {
  constructor(executor) {
    this.state = 'pending';
    this.value = undefined;
    const resolve = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.value = value;
      }
    };
    executor(resolve);
  }
}

Promise.all 实现

MyPromise.all = function(promises) {
  return new Promise((resolve, reject) => {
    const results = [];
    let completed = 0;
    promises.forEach((promise, index) => {
      promise.then(value => {
        results[index] = value;
        if (++completed === promises.length) resolve(results);
      }).catch(reject);
    });
  });
};

Async/Await 高级技巧

错误处理模式

// 方案1: try-catch
async function fetchData() {
  try {
    return await axios.get('/api');
  } catch (err) {
    console.error('Request failed', err);
    throw err; // 继续向上传递
  }
}

// 方案2: 高阶函数包装
function withErrorHandling(fn) {
  return async (...args) => {
    try {
      return await fn(...args);
    } catch (err) {
      sentry.captureException(err);
      return null;
    }
  };
}

并行执行优化

// 低效写法(顺序执行)
async function slow() {
  const a = await fetchA();
  const b = await fetchB();
  return { a, b };
}

// 高效写法(并行执行)
async function fast() {
  const [a, b] = await Promise.all([fetchA(), fetchB()]);
  return { a, b };
}

性能优化实战

微任务优先策略

function heavyTask() {
  // 将CPU密集型任务分解为微任务
  return new Promise(resolve => {
    const chunk = () => {
      if (workQueue.isEmpty()) {
        resolve();
      } else {
        processChunk(workQueue.dequeue());
        Promise.resolve().then(chunk); // 插入微任务队列
      }
    };
    chunk();
  });
}

取消异步流程

function createCancelablePromise(promise) {
  let isCancelled = false;
  const wrappedPromise = new Promise((resolve, reject) => {
    promise.then(
      value => !isCancelled && resolve(value),
      error => !isCancelled && reject(error)
    );
  });
  return {
    promise: wrappedPromise,
    cancel() { isCancelled = true; }
  };
}

可视化辅助理解

同步代码
有任务
无任务
调用栈
执行完毕
检查微任务队列
执行全部微任务
取一个宏任务
60%20%20%任务优先级微任务动画帧宏任务

常见面试题解析

问题1:以下代码输出顺序

setTimeout(() => console.log(1), 0);
Promise.resolve().then(() => console.log(2));
console.log(3);
// 答案: 3 → 2 → 1

问题2:如何实现Promise.race

MyPromise.race = function(promises) {
  return new Promise((resolve, reject) => {
    promises.forEach(promise => {
      promise.then(resolve).catch(reject);
    });
  });
};

问题3:async函数返回什么

async function foo() { return 42; }
const result = foo();
console.log(result instanceof Promise); // true
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐