介绍
- Promise 对象用于表示一个异步操作的最终完成(或失败)及其结果值。— MDN
- 是用于处理异步操作的核心工具
出现原因
- 异步操作更直观,避免嵌套回调
// Promise 出现之前,我们使用事件和回调
const loadScript = (src, callback) => {
// 创建一个 <script> 标签, 并将其添加到页面
let script = document.createElement("script");
script.src = src;
script.onload = () => callback(null, script);
script.onerror = () => callback(new Error(`Script load error for ${src}`));
document.head.append(script);
};
// 此处只加载一个脚本文件,回调看起来还比较清晰,
loadScript(
"https://unpkg.com/vue@3/dist/vue.global.js",
function (error, script) {
if (error) {
console.log(error);
} else {
console.log("loading Vue"); // "loading Vue"
}
}
);
// 但是如果我们想加载多个脚本文件呢?如下所示:
loadScript(
"https://unpkg.com/vue@3/dist/vue.global.js",
function (error, script) {
console.log("loading Vue"); // "loading Vue"
// 嵌套回调
loadScript(
"https://unpkg.com/react@18/umd/react.development.js",
function (error, script) {
console.log("loading React"); // "loading React"
}
);
}
);
- 使用 promise 避免嵌套回调
const loadScript = (src) => {
return new Promise(function (resolve, reject) {
let script = document.createElement("script");
script.src = src;
script.onload = () => resolve(script);
script.onerror = () => reject(new Error(`Script load error for ${src}`));
document.head.append(script);
});
};
// .then 链式调用
loadScript("https://unpkg.com/vue@3/dist/vue.global.js")
.then((script) => {
console.log("loading Vue"); // "loading Vue"
return loadScript("https://unpkg.com/react@18/umd/react.development.js");
})
.then((script) => console.log("loading React")) // "loading React"
.catch((error) => console.log(error));
创建 Promise
- 通过
new Promise()构造函数创建,接收一个执行器函数(executor)
const myPromise = new Promise((resolve, reject) => {
// 异步操作(如 API 请求、定时器等)
if (/* 成功条件 */) {
resolve("Success!"); // 状态变为 fulfilled
} else {
reject("Error!"); // 状态变为 rejected
}
});
状态说明
- new Promise 构造器返回的 pending 对象具有以下内部属性:
- state:
- 初始值是
pending - resolve 调用后变为
fulfilled, - reject 调用之后变为
rejected
- 初始值是
- result:
-初始值是 undefined
- resolve(value) 调用后变为 value
- reject(error) 调用时变为 error
- state:
- 状态一旦改变不可逆
new Promise(() => {}) // 返回 Promise {<pending>}
new Promise((resolve) => { resolve('testB') }) // Promise {<fulfilled>: testB}
new Promise((reject) => { resolve('testC') }) // Promise {<rejected>: testC}
链式调用
- Promise 支持链式调用,
.then、.catch和.finally方法均支持链式调用。- 其中,.then 方法接收两个参数
- 第一个参数处理已决议状态(fulfilled)的回调函数
- 第二个参数则处理已经拒绝(rejected)的回调函数。
- 每一个
.then() 方法返回的是一个新生成的 Promise 对象,这个对象可被用作链式调用。
- 其中,.then 方法接收两个参数
var promiseResolve = new Promise((resolve, reject) => resolve(2));
promiseResolve.then(
res => console.log('resolve', res),
res => console.log('reject', res)
);
// resolve 2
// 单独处理错误
var PromiseReject = new Promise((resolve, reject) => reject(3));
PromiseReject.then(
res => console.log('resolve', res),
res => console.log('reject', res)
);
// reject 3
// rejected 回调和 .catch同时使用,仅触发rejected回调
PromiseReject
.then(
res => console.log('resolve', res),
res => console.log('reject', res)
).catch(
err => console.log('catch', err)
);
// reject 3
// Promise 的`.then()`方法会返回一个新的 Promise,这使得可以进行链式调用
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 1000);
})
.then((value) => {
console.log(value); // 输出: 1
return value * 2;
})
.then((newValue) => {
console.log(newValue); // 输出: 2
return newValue + 3;
})
.then((finalValue) => {
console.log(finalValue); // 输出: 5
})
.catch((error) => {
console.log(error);
});
// 使用catch自动捕获链条上的所有Promise抛出的错误
PromiseReject
.then((result) => {
console.log(result); // 成功时执行(接收 resolve 的值)
})
.catch((error) => {
console.error(error); // 失败时执行(接收 reject 的值)
})
.finally(() => {
console.log("无论成功/失败都会执行");
});
// 执行顺序
console.log(1)
new Promise((resolve) => {
// 立即执行
console.log(2)
resolve(4)
}).then(res => {
// 异步执行
console.log(res)
})
console.log(3)
// 返回 1 2 3 4 5
Promise.resolve() / Promise.reject()
- 快速创建已解决/已拒绝的 Promise
Promise.resolve("立即成功").then(console.log); // 输出 "立即成功"
Promise.reject("立即失败").catch(console.error); // 输出 "立即失败"
与 async/await 结合
- Promise 是
async/await的底层机制:
async function fetchData() {
try {
const result = await myPromise; // 等待 Promise 解决
console.log(result);
} catch (error) {
console.error(error);
}
}