介绍 Promise
- Promise
- 一个包含异步操作结果(将来结果)的占位符对象。
Promise 的优点:
- 无需依赖将事件和回调传递给异步函数,就可以处理异步结果
- 可为一系列异步操作提供 Promise 链式调用,从而避免回调地狱(Callback Hell)
Promise 生命周期:
- Pending:构建 Promise 对象时的初始状态,内部还是立即执行的同步代码
new Promise()
- Settled:异步任务执行完毕
- Fulfilled:异步任务执行成功,且结果可用
then()
- Rejected:异步任务执行失败,即发生了错误
then(onFulfilled[, onRejected])
或catch()
- Fulfilled:异步任务执行成功,且结果可用
构建 Promise
Promise 是一个特殊的对象,接收一个执行器(executor)函数,其中执行器函数包含两个参数:
resolve
:代表处理成功时的回调函数reject
:代表处理失败时的回调函数
JavaScript
1const lotteryPro = new Promise((resolve, reject) => {
2 if (Math.random() >= 0.5) {
3 resolve('恭喜,您中奖啦!!!');
4 } else {
5 reject(new Error('很遗憾,您未中奖'));
6 }
7});
8
9lotteryPro
10 .then(res => console.log(res))
11 .catch(err => console.error(err.message));
此外,还可以使用 Promise.resolve
或 Promise.reject
来构建立即执行的 Promise。
JavaScript
1Promise.resolve('结果').then(res => console.log(res));
2
3Promise.reject(new Error('错误'))
4 .catch(err => console.error(err.message));
Promise ≠ 异步
Promise 不等于异步:Promise 不会也不能将同步代码转为异步代码,它的作用仅仅是包装异步代码,从而使调用异步变得更加优雅,并使之支持 async
/await
关键字。
JavaScript
1const startMilli = Date.now();
2console.log(`1:开始执行`);
3
4// Promise 不能也不会将同步代码转换为异步代码
5new Promise(resolve => {
6 // 假设正在运行一段耗时代码
7 const start = Date.now();
8
9 while (Date.now() - start <= 2000) {
10 // 模拟2秒耗时操作
11 }
12
13 resolve('2秒 Promise');
14})
15 .then(data => console.log(data));
16
17// 该代码会被阻塞至少2秒
18const duration = Math.trunc((Date.now() - startMilli) / 1000);
19console.log(`2:结束执行,耗时:${duration}秒`);
20
21// 1:开始执行
22// 2:结束执行,耗时:2秒
23// 2秒 Promise
Promisifying
- Promisifying
- 将基于回调的异步代码转换为基于 Promise 的异步代码。
setTimeout
JavaScript
1// 因为 `setTimeout` 不会返回错误,故只需要 `resolve` 即可
2const wait = seconds =>
3 new Promise(resolve => setTimeout(resolve, seconds * 1000));
4
5// 使用 Promisifying `setTimeout`
6wait(1)
7 .then(() => {
8 console.log('1秒后执行');
9
10 return wait(1);
11 })
12 .then(() => {
13 console.log('2秒后执行');
14
15 return wait(1);
16 })
17 .then(() => {
18 console.log('3秒后执行');
19
20 return wait(1);
21 })
22 .then(() => {
23 console.log('4秒后执行');
24
25 return wait(1);
26 });
回调地狱(Callback Hell):
JavaScript
1setTimeout(() => {
2 console.log('1秒后执行');
3
4 setTimeout(() => {
5 console.log('2秒后执行');
6
7 setTimeout(() => {
8 console.log('3秒后执行');
9
10 setTimeout(() => {
11 console.log('4秒后执行');
12 }, 1000);
13 }, 1000);
14 }, 1000);
15}, 1000);
Geolocation
JavaScript
1navigator.geolocation.getCurrentPosition(
2 pos => console.log(pos),
3 err => console.error(err.message)
4);
5
6// Promisifying
7const geoPro = new Promise((resolve, reject) => {
8 navigator.geolocation.getCurrentPosition(resolve, reject);
9});
10
11geoPro
12 .then(pos => console.log(pos))
13 .catch(err => console.error(err.message));
14
15console.log('获取位置');
DOM 加载图片
JavaScript
1const body = document.querySelector('body');
2
3(() => {
4 // DOM 加载图片是一个异步操作
5 const img = document.createElement('img');
6 img.src = 'qgs.png';
7
8 img.addEventListener('load', () => {
9 body.insertAdjacentElement('afterbegin', img);
10 });
11})();
12
13// Promisifying
14const createImage = imgPath =>
15 new Promise((resolve, reject) => {
16 const img = document.createElement('img');
17 img.src = imgPath;
18
19 img.addEventListener('load', () => {
20 resolve(img);
21 });
22
23 img.addEventListener('error', () => {
24 reject(new Error('未找到图片'));
25 });
26 });
27
28createImage('j.png')
29 .then(img => {
30 body.insertAdjacentElement('afterbegin', img);
31 })
32 .catch(err => console.error(err.message));
33
34console.log('DOM 开始加载图片');