目录
1,Promise A+规范
1,所有的异步场景,都应该看做是一个异步任务
在 js 中表现为一个对象——Promise 对象。也就是任务对象。
2,Promise 对象有2个阶段,3个状态
1,任务创建:
- 任务总是从未决阶段 --> 已决阶段,无法逆行。
- 任务总是从挂起状态 --> 完成或失败状态,无法逆行。
- 任务一开始都是 pending 状态,任务一旦完成或失败,状态不能再被改变。
const result = new Promise((resolve, reject) => {
resolve(1);
reject(2); // 无效
resolve(3); // 无效
console.log(123); // 正常执行
});
console.log(result); // Promise {<fulfilled>: 1}
2,更改状态:
- 从
pending --> fulfilled
称为resolve(data)
- 从
pending --> rejected
称为reject(reason)
3,后续处理:
- 对
fulfilled
的后续处理,称为onFulfilled
- 对
rejected
的后续处理,称为onRejected
2,Promise 简单API
1,创建任务
const pro = new Promise(() => {
console.log('会被立即执行的函数');
})
console.log(pro) // Promise { <pending> }
2,更改状态
const pro = new Promise((resolve, reject) => {
console.log('会被立即执行的函数')
setTimeout(() => {
if (Math.random() < 0.5) {
resolve('成功') // 从 pending 状态 --> fulfilled 状态
} else {
reject('失败') // 从 pending 状态 --> rejected 状态
}
}, 1000);
})
3,后续处理
pro.then(
// fulfilled 的回调函数
(data) => {
console.log(data)
},
// rejected 的回调函数
(reason) => {
console.log(reason)
}
)
实践举例:delay 延迟工具函数
function delay(duration) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, duration);
});
}
await delay(3000)
3,链式调用
通过 then()
和 catch()
函数做后续处理。
promise.then(
// fulfilled 的回调函数
(data) => {
console.log(data)
},
// rejected 的回调函数
(reason) => {
console.log(reason)
}
)
// 相当于
promise
.then(
// fulfilled 的回调函数
(data) => {
console.log(data);
}
)
.catch(
// rejected 的回调函数
(reason) => {
console.log(reason);
}
);
常见写法:
/*
* 任务成功后,执行处理1,失败则执行处理2
*/
promise.then(处理1).catch(处理2)
/*
* 任务成功后,依次执行处理1、处理2,若 promise 任务失败 或 处理1和2有错,都会执行处理3
*/
promise.then(处理1).then(处理2).catch(处理3)
特性:
3.1,then()必定返回一个新 Promise 对象(新任务)。
根据上面的等效写法,catch()
也会返回一个新 Promise 对象(新任务)。
3.2,新任务的状态,取决于前任务的后续处理。
- 若没有相关的后续处理,新任务的状态和前任务一致,数据为前任务的数据。
换句话说,不相关的后续处理函数不会执行。
下面的例子中,因为 Promise 一开始的状态时
pending
,setTimeout
为了获取最终状态。
至于setTimeout
为什么可以获取,参考事件循环机制
举例1,promise1
是 fulfilled
状态,但却没有 then()
做对应的后续处理。
const promise1 = new Promise((resolve) => {
resolve(1);
});
const promise2 = promise1.catch(() => {
console.log("不会被打印");
});
setTimeout(() => {
console.log(promise2); // Promise {<fulfilled>: 1}
});
举例2,promise1
是 rejected
状态,但却没有 catch()
做对应的后续处理。
const promise1 = new Promise((resolve, reject) => {
reject(1);
});
const promise2 = promise1.then(() => {
console.log("不会被打印");
});
setTimeout(() => {
console.log(promise2); // Promise {<rejected>: 1}
});
- 若有后续处理但还未执行,新任务挂起。
const promise1 = new Promise((resolve) => {
console.log(1);
setTimeout(() => {
resolve();
}, 1000);
});
const promise2 = promise1.then(() => {
console.log(2);
});
setTimeout(() => {
console.log(promise2);
});
// 1
// Promise {<pending>}
// 2
- 若后续处理执行了,则根据后续处理的情况确定新任务的状态:
- 后续处理执行无错,新任务的状态为完成,数据为后续处理的返回值(没有返回,就是 undefined)
- 后续处理执行有错,新任务的状态为失败,数据为异常对象
- 后续执行后返回的是一个任务对象,新任务的状态和数据与该任务对象一致
第1种情况举例:
const promise1 = new Promise((resolve) => {
resolve();
});
const promise2 = promise1.then(() => {
return 123;
});
setTimeout(() => {
console.log(promise2); // Promise {<fulfilled>: 123}
});
const promise1 = new Promise((resolve, reject) => {
reject();
});
const promise2 = promise1.catch(() => {
return 123;
});
setTimeout(() => {
console.log(promise2); // Promise {<fulfilled>: 123}
});
第2种情况举例,catch
同理。
const promise1 = new Promise((resolve) => {
resolve();
});
const promise2 = promise1.then(() => {
throw "一个错误";
});
setTimeout(() => {
console.log(promise2); // Promise {<rejected>: '一个错误'}
});
第3种情况举例,
const promise1 = new Promise((resolve) => {
resolve();
});
const promise2 = promise1.then(() => {
// promise2 的状态取决于这个 Promise 对象的状态
return new Promise((resolve, reject) => {
resolve(1);
});
});
setTimeout(() => {
console.log(promise2); // Promise {<fulfilled>: 1}
});
一道面试题
const result = new Promise((resolve) => {
resolve(1);
})
.then((res) => {
console.log(res); // 1
return new Error(2); // 注意,这不是报错,而是一个对象
})
// 不执行
.catch((err) => {
throw err;
})
// 对上一个 then 返回的 Promise 做了处理,但没有返回结果。
.then((res) => {
console.log(res);
});
setTimeout(() => {
console.log(result); // Promise {<fulfilled>: undefined}
});
3,Promise 静态方法
任务即
Promise
对象
静态方法 | 作用 |
---|---|
Promise.resolve() | 直接返回 fulfilled 状态的任务 |
Promise.reject() | 直接返回 rejected 状态的任务 |
Promise.all(任务数组) | 返回一个数组 任务全部成功则成功 任何一个失败则失败 |
Promise.any(任务数组) | 返回一个任务 任何一个成功则成功 任务全部失败则失败,并返回一个数组 |
Promise.race(任务数组) | 返回一个任务 只要有一个进入已决状态,则已决,状态和其一致 |
Promise.allSettled(任务数组) | 返回一个数组 任务数组全部已决则成功 该任务不会失败 |
主要介绍下 Promise.allSettled(任务数组)
1,当任务数组都变为已决状态,则返回每个任务的结果。
Promise.allSettled([
Promise.resolve(1),
Promise.reject(2),
new Promise((resolve) => {
resolve(3)
})
]).then((values) => {
console.log(values);
});
结果:
2,当任务数组中有一个未决,则永远处于 pending 状态。
Promise.allSettled([
Promise.resolve(1),
Promise.reject(2),
new Promise(() => {})
]).then((values) => {
console.log(values); // then() 永远不被执行
});
实用举例:需要获取所有的请求结果,有失败的请求没有关系,最后能获取所有成功的数据即可。
// 模拟请求
function getData(pageIndex) {
return new Promise((resolve, reject) => {
if (Math.random() < 0.4) {
reject("网络错误");
}
setTimeout(() => {
resolve(pageIndex);
}, Math.floor(Math.random() * 3000));
});
}
const arr = [];
for (let i = 0; i < 5; i++) {
arr.push(getData(i));
}
Promise.allSettled(arr).then((values) => {
console.log(values);
});
结果
4,async 和 await
async
1,async
关键字用于修饰函数,被它修饰的函数,一定返回 Promise 对象。
async function fun() {}
console.log(fun()) // Promise {<fulfilled>: undefined}
async function fun2() {
await 1
}
console.log(fun2()) // Promise {<pending>}。因为有异步代码
2,若执行过程报错,则任务是 rejected
async function fun() {
throw new Error(1);
}
console.log(fun()); // Promise {<rejected>: Error: 1
3,当 async
修饰的函数中明确返回了 Promise 对象,则该函数相当于没有被 async
修饰。
async function fun() {
return new Promise((resolve) => {
resolve(1);
});
}
await
1,await
用于等待一个 Promise 对象已决后,获取已决后的结果,如果结果为 rejected
状态,则抛出异常,可以用 try...catch
捕获。
async function fun() {
try {
await Promise.reject(1);
} catch (error) {
console.log('error:' + error);
}
}
fun() // error:1
2,因为 await
需要放到异步函数中,所以可以用立即执行函数。
(async ()=> {
await delay(1000)
console.log('等待1s后执行后续操作');
})()
3,当 await
后的表达式的值不是 Promise,await
会把该值转换为 fulfilled
状态的 Promise,然后返回其结果。
await 1 //相当于 await Promise.resolve(1)
5,面试题
以上。