Promise

Promise 是 JS 中处理异步操作的一种规范,用于解决传统回调函数嵌套,让异步代码的逻辑更清晰,便于维护。Promise 表示一个异步操作的最终完成或失败及其结果值。有三种状态:

  • pending(进行中):初始状态,既没有成功也没有失败
  • fulfilled(已成功):操作完成
  • rejec(已失败):操作失败
    状态一旦改变就不可逆。

概述

  • 在 JavaScript 中,Promise 不会创建新的线程。因为 Js 是单线程的,浏览器和 node.js 的引擎只有一个主线程,所有同步代码和异步回调最终都会在主线程中执行。单线程设计是为了避免多线程带来的复杂问题(线程同步、资源竞争等),适合处理 DOM 操作场景。

Promise 本身是一个状态管理工具、用于规范异步操作的流程,他用来管理异步操作的 3 种状态,提供链式调用的方式,增强代码的可读性。Promise 的异步操作不会阻塞主线程,是依赖浏览器和 Node.js 的多线程环境,而并不是 js 引擎创建了一个新线程

执行同步代码的流程;

1
2
3
4
5
6
7
8
console.log("1");
const promise = new Promise((resolve) => {
console.log("2"); // 同步执行
setTimeout(() => {
resolve("3"); // 异步操作(由浏览器定时器线程处理)
}, 1000);
});
console.log("4");

输出顺序是:1 → 2 → 4(3 会在 1 秒后通过回调执行)。

用法

Promise 对象

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
const promise = new Promise((resolve, reject) => {
// 执行异步操作
setTimeout(() => {
const success = true;
if (success) {
// 操作成功,调用 resolve 并传递结果
resolve("操作成功的结果");
} else {
// 操作失败,调用 reject 并传递错误信息
reject(new Error("操作失败的原因"));
}
}, 1000);
});
  • resolve:将 Promise 状态从 pending 改为 fulfilled,并传递成功结果
  • reject:将 Promise 状态从 pending 改为 rejected,并传递失败原因

处理 Promise 结果

使用 then() 和 catch() 方法处理异步操作的结果:

1
2
3
4
5
6
7
8
9
promise
.then((result) => {
// 处理成功的结果(fulfilled 状态)
console.log("成功:", result);
})
.catch((error) => {
// 处理失败的原因(rejected 状态)
console.error("失败:", error.message);
});

链式调用

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 传统回调地狱
doSomething(function (result) {
doSomethingElse(
result,
function (newResult) {
doThirdThing(
newResult,
function (finalResult) {
console.log("最终结果:", finalResult);
},
failureCallback
);
},
failureCallback
);
}, failureCallback);

// Promise 链式调用
doSomething()
.then((result) => doSomethingElse(result))
.then((newResult) => doThirdThing(newResult))
.then((finalResult) => console.log("最终结果:", finalResult))
.catch((error) => console.error("任何步骤出错:", error));

每一个 then 会返回一个新的 Promise 对象,并将这个返回的对象传递给下一个 then()的参数并开始执行下一个 then()。
catch()用来监听所有的 then(),如果有任何一个 then()产生错误,都会执行 catch()语句

常用方法

  1. Promise.resolve():快速创建一个已成功的 Promise
    1
    2
    const resolvedPromise = Promise.resolve("直接成功");
    resolvedPromise.then((result) => console.log(result)); // 输出: 直接成功
  2. Promise.reject():快速创建一个已成功的 Promise
    1
    2
    const rejectedPromise = Promise.reject(new Error("直接失败"));
    rejectedPromise.catch((error) => console.error(error)); // 输出: Error: 直接失败
  3. Promise.all():接收一个 Promise 数组,等待所有 Promise 都成功才返回成功结果数组;只要有一个失败就立即返回失败:

    1
    2
    3
    4
    5
    6
    7
    const promise1 = Promise.resolve(1);
    const promise2 = Promise.resolve(2);
    const promise3 = Promise.resolve(3);

    Promise.all([promise1, promise2, promise3])
    .then((results) => console.log(results)) // 输出: [1, 2, 3]
    .catch((error) => console.error(error));

async/await

async/await 是 ES2017(ES8)引入的语法糖,基于 Promise 实现,用于简化异步代码的编写。它让异步代码看起来和同步代码一样直观,彻底解决了回调地狱问题,

概述

async:用于修饰函数,表明函数是一个异步函数,函数执行后会自动返回一个 Promise 对象。
await:只能在 async 函数内部使用,用于等待一个 Promise 对象的成功或者失败,并获取其结果。await 后面通常跟一个 Promise 对象,它会暂停当前 async 函数的执行,等待 Promise 状态改变后再继续

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function riskyOperation() {
return new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("操作失败")), 1000);
});
}

async function handleError() {
try {
// 等待可能失败的 Promise
const result = await riskyOperation();
console.log("成功:", result);
} catch (error) {
// 捕获失败的原因
console.error("出错:", error.message); // 输出: 出错: 操作失败
} finally {
// 无论成功失败都会执行
console.log("操作结束");
}
}

handleError();

对无依赖的异步操作,滥用 await 会导致性能下降(串行执行比并行慢),应优先用 Promise.all()。