提示:以下是本篇文章正文内容,下面案例可供参考
Promise 是 JavaScript 中用于处理异步操作的一种对象。它表示一个异步操作的最终完成(或失败)及其结果值。Promise 提供了一种更清晰、更结构化的方式来处理异步代码,相较于传统的回调函数,它避免了回调地狱的问题。
一、基本概念
一个 Promise 对象有以下几个状态:
pending
:初始状态,既不是成功也不是失败状态。fulfilled
:操作成功完成。rejected
:操作失败。
一旦 Promise 状态从 pending
转变为 fulfilled
或 rejected
,它就会保持这个状态,不会再改变。这称为 Promise 的“不可变性”。
二、使用步骤
1.创建一个 Promise
通过 new Promise 构造函数创建一个 Promise 对象:
代码如下(示例):
const myPromise = new Promise((resolve, reject) => {
// 执行一些异步操作,例如一个异步请求
//resolve函数的作用:在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
//reject函数的作用:在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
setTimeout(() => {
const success = true; // 这是一个示例条件
if (success) {
resolve('Operation successful'); // 操作成功
} else {
reject('Operation failed'); // 操作失败
}
}, 1000);
});
2.使用 then 和 catch
可以使用 then 方法来指定当 Promise 成功时要执行的回调函数,使用 catch 方法来指定当 Promise 失败时要执行的回调函数。
代码如下(示例):
myPromise
.then(result => {
console.log(result); // 输出: Operation successful
})
.catch(error => {
console.error(error); // 输出: Operation failed
});
3.使用 finally
finally 方法用于指定不论 Promise 最终状态如何都会执行的回调函数,用于进行一些清理操作。
代码如下(示例):
myPromise
.then(result => {
console.log(result);
})
.catch(error => {
console.error(error);
})
.finally(() => {
console.log('Cleanup'); // 总会执行
});
4.使用 Promise.all
Promise.all:当所有的 Promise 都成功时才会成功,如果其中任何一个 Promise 失败,则整个 Promise.all 失败。
代码如下(示例):
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then(values => {
console.log(values); // [3, 42, "foo"]
});
5.使用 Promise.race
Promise.race:只要有一个 Promise 成功或失败,就会立即返回那个 Promise 的结果,并且不管其他 Promise 是否完成。
代码如下(示例):
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one');
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'two');
});
Promise.race([promise1, promise2]).then(value => {
console.log(value); // "two"
});
三、执行顺序
在 JavaScript 中,Promise 的执行顺序遵循以下规则:
-
同步执行
:Promise 的执行是同步的,new Promise 会立即执行其传入的执行器函数,而不会等待当前执行栈中的代码执行完毕。 -
异步操作
:Promise 的执行器函数中通常包含异步操作,比如异步请求、定时器等。这些异步操作不会阻塞 Promise 的执行,而是会继续执行后续的代码。 -
then 方法
:当 Promise 对象的状态发生变化(从 pending 变为 fulfilled 或 rejected)
,会调用与之对应的 then 或 catch 方法中注册的回调函数。 -
微任务队列
:then 和 catch 注册的回调函数属于微任务
,它们会在当前宏任务执行完毕后立即执行。如果有多个 then 或 catch 方法,它们的回调函数会按照注册的顺序依次执行。 -
Promise 链
:如果在一个 then 方法中返回了一个新的 Promise 对象,则该 Promise 链会继续执行,新的 Promise 对象的状态变化会触发后续的 then 或 catch 方法中的回调函数执行。 -
其他微任务和宏任务
:在 then 或 catch 回调函数执行完毕后,还可能存在其他微任务(比如 process.nextTick、MutationObserver)和宏任务(比如定时器、I/O 操作)需要执行。
综上所述,Promise 的执行顺序可以概括为:同步执行 Promise 构造函数中的执行器函数
=> 异步操作继续执行
=> 执行 then 或 catch 注册的回调函数
=> 继续执行后续的微任务和宏任务
。
注:当同步代码执行完毕后,就会执行所有的宏任务,宏任务执行完成后,会判断是否有可执行的微任务;如果有,则执行微任务,完成后,执行宏任务;如果没有,则执行新的宏任务,形成事件循环。
四、示例
1.异步请求
代码如下(示例):
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const data = { some: 'data' };
const success = true;
if (success) {
resolve(data);
} else {
reject('Error fetching data');
}
}, 2000);
});
}
fetchData()
.then(data => {
console.log('Data received:', data); // 输出: Data received: { some: 'data' }
})
.catch(error => {
console.error(error); // 例如:Error fetching data
});
2.执行顺序
console.log('Start'); // 同步代码1 1
const promise1 = new Promise((resolve, reject) => {
console.log('Promise1 Executor Start'); // 同步代码2 2
setTimeout(() => {
resolve('Promise1 Resolved');
console.log('Promise1 Timer Finished'); // 异步代码1 10
}, 1000);//1s后执行
console.log('Promise1 Executor End'); // 同步代码3 3
});
promise1.then(value => {
console.log(value); // 异步代码2 -> 微任务1 11
});
console.log('After Promise1'); // 同步代码4 4
const promise2 = new Promise((resolve, reject) => {
console.log('Promise2 Executor Start'); // 同步代码5 5
setTimeout(() => {
resolve('Promise2 Resolved');
console.log('Promise2 Timer Finished'); // 异步代码3 8
}, 500);//0.5s后执行
console.log('Promise2 Executor End'); // 同步代码6 6
});
promise2.then(value => {
console.log(value); // 异步代码4 -> 微任务2 9
});
console.log('End'); // 同步代码7 7
//输出结果
//Start
//Promise1 Executor Start
//Promise1 Executor End
//After Promise1
//Promise2 Executor Start
//Promise2 Executor End
//End
//Promise2 Timer Finished
//Promise2 Resolved
//Promise1 Timer Finished
//Promise1 Resolved
分析执行顺序:
- 同步代码执行:
- console.log(‘Start’); 输出:
Start
- 执行 new Promise 构造函数中的同步部分:
- console.log(‘Promise1 Executor Start’); 输出:
Promise1 Executor Start
- setTimeout 注册一个定时器(1秒后执行)
- console.log(‘Promise1 Executor End’); 输出:
Promise1 Executor End
- console.log(‘Promise1 Executor Start’); 输出:
- console.log(‘After Promise1’); 输出:
After Promise1
- 执行 new Promise 构造函数中的同步部分:
- console.log(‘Promise2 Executor Start’); 输出:
Promise2 Executor Start
- setTimeout 注册一个定时器(0.5秒后执行)
- console.log(‘Promise2 Executor End’); 输出:
Promise2 Executor End
- console.log(‘End’); 输出:
End
- console.log(‘Promise2 Executor Start’); 输出:
- console.log(‘Start’); 输出:
- 异步代码执行:
- 0.5秒后,Promise2 的定时器触发:
- resolve(‘Promise2 Resolved’) 将 promise2 状态变为 fulfilled
- console.log(‘Promise2 Timer Finished’); 输出:
Promise2 Timer Finished
- promise2.then
注册的回调被推入微任务队列
- 1秒后,Promise1 的定时器触发:
- resolve(‘Promise1 Resolved’) 将 promise1 状态变为 fulfilled
- console.log(‘Promise1 Timer Finished’); 输出:
Promise1 Timer Finished
- promise1.then
注册的回调被推入微任务队列
- 0.5秒后,Promise2 的定时器触发:
- 微任务执行:
- 执行 promise2.then 注册的回调:
console.log(‘Promise2 Resolved’); 输出:Promise2 Resolved
- 执行 promise1.then 注册的回调:
console.log(‘Promise1 Resolved’); 输出:Promise1 Resolved
- 执行 promise2.then 注册的回调:
总结
Promise 是现代 JavaScript 中处理异步操作的核心内容,通过它可以让异步代码更加清晰易读。