JavaScript 异步编程

时游大约 2 分钟

JavaScript 异步编程

JavaScript 是单线程语言,异步编程是处理耗时操作(如网络请求、定时任务)的关键。

回调函数 (Callbacks)

最基础的异步处理方式,但容易导致“回调地狱”。

function getData(callback) {
    setTimeout(() => {
        callback("Data loaded");
    }, 1000);
}

getData((data) => {
    console.log(data);
    // 嵌套回调...
});

Promise

Promise 对象代表一个异步操作的最终完成(或失败)及其结果值。解决了回调地狱的问题。

const myPromise = new Promise((resolve, reject) => {
    setTimeout(() => {
        const success = true;
        if (success) {
            resolve("Operation success");
        } else {
            reject("Operation failed");
        }
    }, 1000);
});

myPromise
    .then(result => {
        console.log(result);
        return "Next step";
    })
    .then(next => {
        console.log(next);
    })
    .catch(error => {
        console.error(error);
    })
    .finally(() => {
        console.log("Done");
    });

Promise.all

并行执行多个 Promise,全部成功才成功,有一个失败则失败。

const p1 = Promise.resolve(1);
const p2 = new Promise(resolve => setTimeout(() => resolve(2), 1000));

Promise.all([p1, p2]).then(values => {
    console.log(values); // [1, 2]
});

Promise.race

返回第一个完成(无论成功或失败)的 Promise 的结果。

const p1 = new Promise(resolve => setTimeout(() => resolve("Fast"), 100));
const p2 = new Promise(resolve => setTimeout(() => resolve("Slow"), 500));

Promise.race([p1, p2]).then(value => {
    console.log(value); // "Fast"
});

Async/Await

ES2017 引入的语法糖,基于 Promise,使异步代码看起来像同步代码,可读性极高。

  • async 函数返回一个 Promise。
  • await 只能在 async 函数内部使用,等待 Promise 解决。
function delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function fetchUser() {
    try {
        console.log("Start fetching...");
        await delay(1000); // 模拟网络延迟
        const user = { id: 1, name: "Async User" };
        console.log("User fetched:", user);
        return user;
    } catch (error) {
        console.error("Error:", error);
    }
}

// 错误处理模式
async function errorHandling() {
    // 方式 1: try-catch
    try {
        await Promise.reject("Oops");
    } catch (e) {
        console.log("Caught:", e);
    }

    // 方式 2: catch() 链式调用
    await Promise.reject("Oops 2").catch(e => console.log("Caught 2:", e));
}

fetchUser();

串行 vs 并行

async function serial() {
    await delay(1000);
    await delay(1000);
    console.log("2 seconds passed");
}

async function parallel() {
    const p1 = delay(1000);
    const p2 = delay(1000);
    await p1;
    await p2;
    console.log("1 second passed (approx)");
}

Event Loop (事件循环)

JavaScript 运行时模型基于“事件循环”。

  1. 调用栈 (Call Stack): 执行同步代码。
  2. 任务队列 (Task Queue / Callback Queue): 存放宏任务 (MacroTask),如 setTimeout, setInterval, I/O。
  3. 微任务队列 (Microtask Queue): 存放微任务 (MicroTask),如 Promise.then, process.nextTick (Node.js)。

执行顺序:

  1. 执行栈中的同步代码。
  2. 清空微任务队列中的所有任务。
  3. 从宏任务队列中取出一个任务执行。
  4. 重复步骤 2-3。
console.log('1'); // 同步

setTimeout(() => {
    console.log('2'); // 宏任务
}, 0);

Promise.resolve().then(() => {
    console.log('3'); // 微任务
});

console.log('4'); // 同步

// 输出顺序: 1 -> 4 -> 3 -> 2
上次编辑于:
贡献者: 15327360835
Loading...