常见的任务处理代码
//任务成功后,执行处理1,失败则执行处理2
pro.then(处理1).catch(处理2)
//任务成功后,依次执行处理1,处理2
pro.then(处理1).then(处理2)
//任务成功后,依次执行处理1,处理2,若任务失败或前面的处理有错,执行处理3
pro.then(处理1).then(处理2).catch(处理3)
promise的链式调用
新任务的状态取决于后续处理
- 若没有相关的后续处理,新任务的状态和前任务一样,数据为前任务的数据
- 若有后续处理但是还没执行(之前任务有异步处理),新任务的状态为pending
- 后续处理执行了,看处理函数执行的过程
-
处理函数正常运行,新任务为fulfilled,数据为后续处理的返回值
-
处理函数报错,新任务为rejected,数据为异常对象
-
处理函数返回一个任务对象,新任务的状态和数据与该任务对象一致
-
题1
const pro1 = new Promise((resolve) => {
setTimeout(() => {
resolve(1);
}, 1000);
})
const pro2 = pro1.then((data) => {
console.log(data);
return data + 1;
});
const pro3 = pro2.then((data) => {
console.log(data);
});
console.log(pro1, pro2, pro3);
setTimeout(() => {
console.log(pro1, pro2, pro3);
}, 2000);
输出结果
分析
pro1一开始的状态是pending,由于pro2和pro3依赖pro1,所以
- pro1 pending
- pro2 pending
- pro3 pending 过了一秒钟之后,pro1通过resolve达到fulfilled,pro1后续处理函数正常运行,返回值为1+1,所以pro2的状态是fulfilled,数据为2,同时输出1,pro2后续处理函数正常运行,但是没有返回值,所以pro3的状态为fulfilled,数据为undefined,同时输出2。
题2
new Promise((resolve, reject) => {
resolve(1);
}).then((data) => {
console.log(data);
return 2;
}).catch((err) => {
return 3;
}).then((data) => {
console.log(data);
})
分析:
pro1一开始就resolevd了,所以状态为fulfilled,数据为1。
pro2是pro1的后续处理,then是针对成功进行处理,pro1成功了,所以pro2要看他的处理函数,处理函数输出pro1的数据,返回2,那么2就是pro2的数据,同时pro2的状态变为fulfilled。
pro3是pro2的后续处理,由于catch是针对错误的,但是pro2没有对错误处理,所以pro3就是pro2的状态和数据
pro4是pro3的后续处理,then是针对成功的,看pro3的状态为fulfilled为成功,且处理函数没有错误,那么pro4就为fulfilled,数据为undefined。
- pro1 fulfilled 1
- pro2 fulfilled 2
- pro3 fulfilled 2
- pro3 fulfilled undefined
结果: 输出:1 2
题3
new Promise((resolve, reject) => {
resolve();
}).then((data) =>{
console.log(data.toString());
return 2;
}).catch((data)=>{
return 3;
}).then((data) => {
console.log(data);
})
/**
* pro1 fulfilled undefined
* pro2 rejected 报错
* pro3 fulfilled 3
* pro4 fulfilled undefined
*/
// 输出3
题4
new Promise((resolve, reject) => {
throw new Error(1);
}).then((data) => {
console.log(data);
return new Error('2');
}).catch(err => {
throw err;
return 3;
}).then((res) => {
console.log(res);
})
/**
* pro1 rejected error(1)
* pro2 rejected error(1)
* pro3 rejected error(1)
* pro4 rejected undefined
*/
// 无输出,会有报错
题5
const pro1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject();
}, 1000);
})
const pro2 = pro1.catch((err) => {
return 2;
})
console.log(pro1, pro2);
setTimeout(() =>{
console.log(pro1, pro2);
}, 2000)
/**
* pro1 pending
* pro2 pending
*
* 1s后
* pro1 rejected undefined
* pro2 fulfilled 2
*/
Promise API
| 方法 | 含义 |
|---|---|
| Promise.resolve() | 返回一个完成状态的任务 |
| Promise.reject() | 返回一个拒绝状态的任务 |
| Promise.all(任务数组) | 返回一个任务,任务数组全部成功则成功,任何一个失败就失败 |
| Promise.any(任务数组) | 返回一个任务,任务数组任意一个成功就成功,任务全部失败就失败 |
| Promise.race(任务数组) | 返回一个任务,任务数组任意一个已决则已决,状态和其一致 |
| Promise.allSettled(任务数组) | 返回一个任务,任务数组全部已决则成功,改任务不会失败 |
Promise.resolve(1).then((res) => {
console.log(res);
})
// 相当于下面的代码
new Promise((resolve, reject) => {
resolve(1)
}).catch((data)=>{
console.log(data);
})
Promise.reject(1).catch((res) => {
console.log(res);
})
// 相当于下面的代码
new Promise((resolve, reject) => {
reject(1)
}).catch((data)=>{
console.log(data);
})
- Promise.all(任务数组)
const tesProArr = new Array(10).fill(0).map((item, index) => {
if (Math.random() > 0.99) {
return Promise.reject(index);
}
return Promise.resolve(index);
})
console.log(tesProArr);
const pro = Promise.all(tesProArr);
setTimeout(() => {
console.log(pro);
/**
* Promise { [
0, 1, 2, 3, 4,
5, 6, 7, 8, 9
] }
*/
}, 1000);
任务数组全部成功则成功,返回的是成功的数据,若有失败的,则返回第一个失败的数据。
async
async关键字用于修饰函数,被它修饰的函数,一定返回Promise
async function test(){
return 1;
}
async function test2(){
return Promise.resolve(2);
}
// 上面这段代码相当于没有async
function test2(){
return Promise.resolve(2);
}
async function test3(){
throw new Error(3);
}
await注意点
async function test(){
const a = await 1; // 相当于await Promise.resolve(1);
}
间隔duration打印数字1
function delay(duration){
return new Promise((resolve, reject)=>{
setTimeout(() =>{
resolve(1);
},duration)
})
}
delay(1000).then(res=>{
console.log(res);
})
宏任务和微任务
宏任务:setTimeout、setInterval、事件处理、requestAnimationFrame的回调。
微任务:Promise的then(catch)回调、MutationObserver
为什么要有微任务
按照官方的设想,任务之间是不平等的,有些任务对用户体验影响大,就应该优先执行,而有些任务属于背景任务(比如定时器),晚点执行没有什么问题,所以设计了这种优先级队列的方式。
一波输出题
const pro = new Promise((resolve, reject)=>{
console.log(1);
resolve();
console.log(2);
})
pro.then(()=>{
console.log(3);
})
console.log(4);
// 1,2,4,3
- 分析:
pro: 执行栈: 宏任务: 微任务:pro.then
const pro = new Promise((resolve, reject) => {
console.log(1);
setTimeout(() => {
console.log(2);
resolve();
console.log(3);
})
})
pro.then(() => {
console.log(4);
})
console.log(5);
// 1 5 2 3 4
const pro = new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 1000);
})
const pro2 = pro.catch(()=>{
return 2;
})
console.log(pro); // promise {<pending>}
console.log(pro2); // promise {<pending>}
setTimeout(() => {
console.log(pro); // promise{<fulfilled> undefined}
console.log(pro2); // promise {<fulfilled> undefined}
}, 2000)
async function method() {
console.log(1);
// await代码在then里面
const a = await 2;
console.log(a);
}
// function method() {
// return Promise.resolve(1).then((a) => {
// console.log(a);
// })
// }
method();
console.log(3)
// 1 3 2
promise完成后才会到微队列,await后面的代码是异步的
async function m() {
console.log(0);
const n = await 1;
console.log(n);
}
(async () => {
await m();
console.log(2);
})();
console.log(3);
/**
* 执行m(),输出0,之后输入3,然后微队列中加入输出1,由于await 1的promise是完成状态的,输出1,然后输出2
* 0,3,1,2
*/
async function m1() {
return 1;
}
// console.log(m1()); // promise { 1 };
async function m2() {
const n = await m1();
console.log(n);
return 2;
}
async function m3(){
const n = m2();
console.log(n);
return 3;
}
m3().then((n)=>{
console.log(n);
})
m3();
console.log(4);
/**
* m1 fulfilled 1
* m2 pending
* m3 fulfilled 3
*
* 微队列:输出1 输出3 输出1
*/
/**
* pending pending 4 1 3 1
*/
var a;
var b = new Promise((resolve, reject) => {
console.log('promise1');
setTimeout(() => {
resolve();
}, 1000);
}).then(() => {
console.log('promise2');
}).then(() => {
console.log('promise3');
}).then(() => {
console.log('promise4');
})
a = new Promise((async (resolve, reject) => {
console.log(a);
await b;
console.log(a);
console.log('after1');
// 由于a的状态是pending,没有resolve,所以后面代码不执行
await a;
resolve(true);
console.log('after2');
}))
console.log('end');
// 分析
/**
* a: undefined
* b: undefined
* p1: pending
* p2: pending
* p3: pending
* p4: pending
* */
/**
* a: undefined
* b: p4 promise{pending}
* p1: pending
* p2: pending
* p3: pending
* p4: pending
* */
/**
* a: undefined
* b: p4 promise{fulfilled}
* p1: fulfilled
* p2: fulfilled
* p3: fulfilled
* p4: fulfilled
* p5: pending
* */
/** 输出
promise1
undefined
end
promise2
promise3
promise4
Promise { <pending> }
after1
*/
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(function () {
console.log('setTimeout');
}, 0)
async1();
new Promise((resolve, reject) => {
console.log('promise1');
resolve();
}).then(function () {
console.log('promise2');
})
console.log('script end');
/**
* 宏任务: setTimeout
* 微队列:‘async1 end‘ ’promise2‘
* script start
* async1 start
* async2
* promise1
* script end
* async1 end
* promise2
* setTimeout
*/
手写Promise A+规范
//promise的状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
/**
* 把callback放到微队列中
* @param {Function} callback
*/
function runMicroTask(callback) {
if (process && process.nextTick) { // 在node环境
process.nextTick(callback);
} else if (MutationObserver) { // 在浏览器环境
const observer = new MutationObserver(callback); // 优化:单例
const p = document.createElement('p');
observer.observe(p, {
childList: true, //观察p元素的内部变化
})
p.innerHTML = '1';
} else {
setTimeout(callback, 0);
}
}
/**
* 判断obj是不是Promise
* @param {*} obj
* @return {Boolean} boolean
*/
function isPromise(obj) {
return !!(obj && typeof obj === 'object' && typeof obj.then === 'function');
}
class MyPromise {
/**
* 创建一个Promise
* @param {Function} executor 任务执行器
*/
constructor(executor) {
this._status = PENDING;
this._value = undefined;
this._handler = []; // 存放后续处理函数
try {
// bind绑定当前this,避免外面使用时this的指向出问题
executor(this._resolve.bind(this), this._reject.bind(this));
} catch (error) {
this._reject(error);
}
}
/**
* 改变Promise的状态和数据
* @param {String} status
* @param {*} value
*/
_changeStatus(status, value) {
// 状态一旦改变,就不可以逆转
if (this._status !== PENDING) {
return;
}
this._status = status;
this._value = value;
// 状态发生改变,执行任务队列的
this._runHandler();
}
/**
* 将Promise推向成功的函数
* @param {*} data 数据
*/
_resolve(data) {
this._changeStatus(FULFILLED, data);
}
/**
* 将Promise推向失败的函数
* @param {*} reason
*/
_reject(reason) {
this._changeStatus(REJECTED, reason);
}
/**
* 向队列中加入后续处理函数
* @param {Function} executor 后续处理函数
* @param {String} status 状态
* @param {Function} resolve then返回Promise的resolve函数
* @param {Function} reject then返回Promise的reject函数
*/
_pushHandler(executor, status, resolve, reject) {
this._handler.push({
executor,
status,
resolve,
reject,
});
}
/**
* 根据实际情况执行队列
* @returns
*/
_runHandler() {
if (this._status === PENDING) {
// pending状态啥都不做
return;
}
// 将任务队列中拿出来执行
while (this._handler[0]) {
const handler = this._handler[0];
this._runOneHandle(handler);
this._handler.shift();
}
}
/**
* 处理一个handler
* @param {*} handler
*/
_runOneHandle({
executor,
status,
resolve,
reject
}) {
// 放入微队列中
runMicroTask(() => {
if (this._status !== status) {
// 状态不一致
return;
}
// 传递的后续处理不是一个函数
if (typeof executor !== 'function') {
// 那么要看当前状态
this._status === FULFILLED ? resolve(this._value) : reject(this._value);
return;
}
try {
// 通过参数解构 解决this指向问题
const data = executor(this._value);
if (isPromise(data)) {
data.then(resolve, reject);
} else {
resolve(data);
}
} catch (error) {
reject(error);
}
})
}
/**
* promise A+规范的then
* @param {Function} onFulfilled
* @param {Function} onRejected
* @return {Promise} promise
*/
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
this._pushHandler(onFulfilled, FULFILLED, resolve, reject);
this._pushHandler(onRejected, REJECTED, resolve, reject);
// 加入到任务队列也要看是否执行
this._runHandler();
});
}
/**
* 仅处理失败的场景
* @param {*} onRejected
*/
catch (onRejected) {
return this.then(null, onRejected);
}
/**
* 无论什么情况,都要运行, 并且状态和数据和之前的pro一样,但是报错就报错
* @param {Function} onSettled
*/
finally(onSettled) {
return this.then((data) => {
onSettled();
return data;
}, (reason) => {
onSettled();
throw reason;
});
}
static resolve(data) {
// 传递的本身是ES6的Promise
if (data instanceof MyPromise) {
return data;
}
return new MyPromise((resolve, reject) => {
if (isPromise(data)) {
data.then(resolve, reject);
} else {
resolve(data);
}
})
}
static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(reason);
})
}
}
手写catch和finally
Promise.prototype.catch = function (onRejected) {
return this.then(null, onRejected);
}
Promise.prototype.finally = function (onSettled) {
return this.then((data) => {
onSettled();
return data;
}, (reason) => {
onSettled();
throw reason;
})
}
Promise.resolve()和Promise.reject()
Promise.resolve = function (data) {
// data本身是一个ES6Promise
if (data instanceof Promise) {
return data;
}
return new Promise((resolve, reject) => {
function isPromise(obj) {
return !!(obj && typeof obj === 'object' && typeof obj.then === 'function');
}
// 传递的Promise A+
if (isPromise(data)) {
data.then(resolve, reject);
} else {
resolve(data);
}
})
}
Promise.reject = function (reason) {
return new Promise((resolve, reject) => {
reject(reason);
})
}
Promise.all()
Promise.all = function(arr){
return new Promise((resolve, reject)=>{
try{
let count = 0; // Promise的个数
let fulfilledCount = 0; // 已完成状态的Promise
const result = [];
// arr是一个迭代器 所以用forof循环
for(const p of arr){
let i = count;
count++;
Promise.resolve(p).then((data)=>{
fulfilledCount++;
result[i] = data;
if(fulfilledCount === count){
resolve(result);
}
},reject)
}
if(count === 0){
reject([]);
}
}catch(error){
reject(error);
console.error(error);
}
})
}
Promise.allSettled()
Promise.allSettled = function (pros) {
const ps = [];
for (const p of pros) {
// ps数组的每一项都不可能失败,因为是自己写的
ps.push(Promise.resolve(p).then(data => ({
status: 'fulfilled',
data
}), reason => ({
status: 'rejected',
reason
})))
}
return Promise.all(ps);
}
const pro = Promise.allSettled([1, Promise.resolve(1212), Promise.reject(234)]);
pro.then(res => {
console.log(res);
/** [
{ status: 'fulfilled', data: 1 },
{ status: 'fulfilled', data: 1212 },
{ status: 'rejected', reason: 234 }
]
*/
})
Promise.race()
Promise.race = function(pros){
return new Promise((resolve, reject)=>{
for (const p of pros) {
Promise.resolve(p).then(resolve, reject);
}
})
}