在promise出现之前,对异步请求的处理方式如下
function requestData(url, successCallback, failureCallback) {
// 模拟异步请求
setTimeout(() => {
if (url === "coderwhy") {
//请求成功
const names = ["lily", "koby"];
successCallback(names);
} else {
const errMsg = "请求失败";
failureCallback(errMsg);
}
}, 2000);
}
requestData(
"coderwhy",
(res) => {
console.log("请求成功的结果是", res);
},
(err) => {
console.log("请求失败的结果是", err);
}
);
执行结果:
请求成功的结果是 [ 'lily', 'koby' ]
什么是promise和基本使用
Promise是一个类,可以翻译成承诺、许诺、期约
- 通过new Promise(exector)创建Promise对象时,我们需要传入一个executor回调函数,这个函数会在创建Promise对象时被立即执行
- 执行executor函数时,需要给其传两个回调函数,第一个为resolve函数,第二个为reject函数
- resolve和reject函数都可以接受一个参数
- promise对象有一个then方法,执行then方法需要传入两个回调函数,fulfilled函数和rejected函数
-
在executor函数内部,
- 如果执行了resolve回调函数,则通过then方法传入的fulfilled函数会被执行,resolve执行时传递的参数会作为参数,传给fulfilled函数
- 如果执行了reject函数,则通过then方法传入的rejected函数会被执行,reject执行时传递的参数会作为参数,传给rejected函数
- 可以多次执行promise对象的then函数,注册多个fulfilled和rejected函数
- 通过执行promise对象的then函数,注册的多个fulfilled和rejected函数,在resolve或reject函数被调用时,所有的fulfilled或rejected函数都会被调用
下面是简写Promise类的基本使用的实现过程,用HyPromise这个自定义类表现
class HyPromise {
constructor(executor) {
this.fulfilledFns = [];
this.rejectedFns = [];
//创建对象时,executor函数会被立即执行,并需要传入resolve,reject两个回调函数
const resolve = function (res) {
// resolve函数执行,会立马执行通过执行then方法,传入的fulfilled函数
this.fulfilledFns.forEach((fn) => {
// resolve执行时,接收的参数,会作为通过执行then方法传入的fulfilled函数的参数传入
fn(res);
});
};
const reject = function (err) {
// reject函数执行,会立马执行通过执行then方法,传入的rejected函数
this.rejectedFns.forEach((fn) => {
// reject执行时,接收的参数,会作为通过执行then方法传入的rejected函数的参数传入
fn(err);
});
};
executor(resolve, reject);
}
//给 HyPromise.prototype对象上添加一个then方法, 可以被所有的HyPromise对象调用
// then方法接受两个回调函数
then(fulfilled, rejected) {
//把通过执行then传入的回调存起来,以便resolve和reject回调函数执行的时候调用
this.fulfilledFns.push(fulfilled);
this.rejectedFns.push(rejected);
}
}
下面是promise的基本使用
// 创建一个Promise对象
const promise = new Promise((resolve, reject) => {
// 模拟异步请求
setTimeout(() => {
//请求成功
resolve("请求结果");
//请求失败
// reject('失败原因')
}, 3000);
});
promise.then(
(res) => {
console.log(res);
},
(err) => {
console.log(err);
}
);
// 可以多次执行promise对象的then函数,注册多个fulfilled和rejected函数
promise.then(
(res) => {
console.log(res);
},
(err) => {
console.log(err);
}
);
使用promise对异步请求的处理方式如下
//
function requestData(url) {
return new Promise((resolve, reject) => {
// 模拟异步请求
setTimeout(() => {
if (url === "coderwhy") {
//请求成功
const names = ["lily", "koby"];
resolve(names);
} else {
const errMsg = "请求失败";
reject(errMsg);
}
}, 2000);
});
}
const promise = requestData("coderwhy");
promise.then(
(res) => {
console.log("请求成功的结果是", res);
},
(err) => {
console.log("请求失败的结果是", err);
}
);
promise对象的状态
promise对象有三种状态:
-
待定(pending):初始状态,即没有被兑现,也没有被拒绝
-
已兑现(fulfilled): 意味着操作成功完成
-
已拒绝(rejected):意味着操作失败
-
executor函数中的resolve回调被执行,会把promise对象的状态敲定为fulfilled已兑现状态
-
executor函数中的reject回调被执行,会把promise对象的状态敲定为rejected已拒绝状态
-
执行then方法中的resolved或rejected函数被执行时,promise对象的状态已经被修改了
-
promise对象的状态一旦敲定,就不会被再次修改,即使在executor函数中再调用reject或resolve回到函数,也相当于没有执行
-
exector函数中resolve或reject函数执行,promise对象的状态被敲定,并不会影响下面的代码执行
// 创建一个Promise对象
const promise = new Promise((resolve, reject) => {
// 此时promise对象的状态为pending
// 模拟异步请求
setTimeout(() => {
//请求成功:resolve函数的执行,把promise对象的状态修改为fulfilled
resolve("请求结果");
resolve(
"promise对象的状态一旦被敲定,并不能再被修改,再次执行resolve或reject函数,什么效果都没有"
);
console.log(
"执行resolve函数,promise对象的状态被敲定,并不影响下面代码的执行"
);
//请求失败:reject函数的执行,把promise对象的状态修改为rejected
// reject('失败原因')
}, 3000);
});
promise.then(
(res) => {
// 此时,promise对象的状态已经改为fulfilled
console.log(res);
},
(err) => {
// 此时,promise对象的状态已经改为rejected
console.log(err);
}
);
执行结果:
执行resolve函数,promise对象的状态被敲定,并不影响下面代码的执行
请求结果
promise的resolve回调的参数
promise的resolve回调函数的参数
-
1.普通的值或对象
- promise对象的状态由pending修改为fulfilled
- 此参数直接作为resolved回调的参数传入
-
2.传入一个promise对象newPromise
- 那么当前promise对象的状态由这个新的promise对象newPromise决定,即当前promise对象的状态移交给了这个这个新的promise对象newPromise
- newPromise对象的resolve执行时,传的参数,会作为当前对象的fulfilled回调的参数传入
- newPromise对象的reject执行时,传的参数,会作为当前对象的rejected回调的参数传入
-
3.传入一个实现了then方法的对象obj(即这个对象实现了thenable接口)
- 这个then方法接受两个参数,resolve,reject回调函数
- 当前对象obj的then方法会被立即执行,promise的resolve/reject回调函数会作为then方法的参数传入
- 在then方法内部,
- 如果resolve被执行,当前promise对象的状态会被修改为fulfilled,传的参数,会作为当前对象的fulfilled回调的参数传入
- 如果reject被执行,当前promise对象的状态会被修改为rejected,传的参数,会作为当前对象的rejected回调的参数传入
// resolve参数为一个普通的值或对象
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ name: "why", age: 18 });
});
});
promise.then(
(res) => {
console.log(res);
},
(err) => {
console.log(err);
}
);
// 执行结果:{ name: 'why', age: 18 }
// resolve参数为一个新的promise对象
const newPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(111);
});
});
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(newPromise);
});
});
promise1.then(
(res) => {
console.log(res);
},
(err) => {
console.log(err);
}
);
// 执行结果:111
// resolve参数为一个实现了then方法的对象
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
then(resolve, reject) {
//then方法会立即被执行
resolve("then");
},
});
});
});
promise2.then(
(res) => {
console.log(res);
},
(err) => {
console.log(err);
}
);
// 执行结果:then
promise的then方法
-
同一个promise对象可以多次调用then方法,
- resovle回调执行时,会把所有通过then方法传入的resolved回调函数都执行
- reject回调执行时,会把所有通过then方法传入的rejected回调函数都执行
-
promise对象的then方法执行会返回一个新的promise对象thenPromise
-
此promise对象thenPromise的状态由resolved或rejected回调函数的执行决定
- 当resolved函数return 一个普通的值或对象时,thenPromise对象resolve这个普通的值或对象
- 当resolved函数return 一个新的promise对象时,thenPromise对象的状态由这个新的promise对象决定
- 当resolved函数return 一个实现then方法的对象时,这个对象的then方法会立马执行,
- then方法内执行了resolve,thenPromise对象resolve这个resolve函数执行时传入的参数
- then方法内执行了reject,thenPromise对象reject这个reject函数执行时传入的参数
- 当resolved函数执行过程中抛出了异常,thenPromise对象的状态变为rejected,rejected函数会被执行
-
-
如果promise对象执行了reject回调,状态变为rejected,执行rejected函数,此时promise对象的then返回的thenPromise对象的状态怎么决定呢?
-
只要rejected函数执行时没有抛出异常,thenPromise对象的状态就为fulfilled,执行resolved回调,rejected函数的返回值会作为thenPromise对象的resolved函数的参数传入
- 如果抛出了异常,thenPromise对象的状态就为rejected,执行rejected回调, 异常信息会作为thenPromise对象的rejected函数的参数传入
- catch返回值依然是个promise对象,和then原理一样
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ name: "why", age: 18 });
});
});
//promise.then方法执行返回一个promise对象
//resolved函数执行染回一个普通的值或对象,这个值会作为thenPromise对象的resolve函数的参数传进去
const thenPromise = promise.then(
(res) => {
return "aaa";
},
(err) => {}
);
thenPromise.then(
(res) => {
console.log(res);
},
(err) => {}
);
//执行结果:aaa
//resolved函数执行染回一个新的promise对象newPromise,这个值会作为thenPromise对象的resolve函数的参数传进去
//thenPromise对象的状态由这个新对象newPromise决定
const newPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ name: "why", age: 18 });
});
});
const thenPromise1 = promise.then(
(res) => {
return newPromise;
},
(err) => {}
);
thenPromise1.then(
(res) => {
console.log(res);
},
(err) => {}
);
//执行结果:{ name: "why", age: 18 }
//resolved函数执行返回一个实现了then方法的对象,这个对象的then方法会立即被执行,
//then方法中执行了resolve,则thenPromise对象的状态变为fulfilled,
//then方法中执行了reject,则thenPromise对象的状态变为rejected,
const thenPromise2 = promise.then(
(res) => {
return {
then(resolve, reject) {
resolve("then");
},
};
},
(err) => {}
);
thenPromise2.then(
(res) => {
console.log(res);
},
(err) => {}
);
//执行结果:then
//promise的状态变为了fulfilled,执行了fulfilled函数,fulfilled函数执行过程中抛出异常,
//则promise.then方法返回的promise对象thenPromise3状态变成了rejected,则执行thenPromise3的rejected的回调函数
const thenPromise3 = promise.then(
(res) => {
throw new Promise("fulfilled函数执行报错了");
},
(err) => {}
);
thenPromise3.then(
(res) => {
console.log(res);
},
(err) => {
console.log(err);
}
);
// TypeError: Promise resolver fulfilled函数执行报错了 is not a function
// at new Promise (<anonymous>)
// at G:\03.教学视频\0.javascript-王红元\js高级\code\16.promise\6.promise对象的then方法.js:167:11
如果promise对象执行了reject回调,状态变为rejected,执行rejected函数,此时promise对象的then返回的thenPromise对象的状态怎么决定呢?
- 只要rejected函数执行时没有抛出异常,thenPromise对象的状态就为fulfilled,执行resolved回调,rejected函数的返回值会作为thenPromise对象的resolved函数的参数传入
- 如果抛出了异常,thenPromise对象的状态就为rejected,执行rejected回调, 异常信息会作为thenPromise对象的rejected函数的参数传入
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("报错了啊啊啊");
});
});
const thenPromise4 = promise1.then(
(res) => {
// console.log(res);
},
(err) => {
return 888;
}
);
thenPromise4.then(
(res) => {
console.log(999, res);
},
(err) => {
console.log(err);
}
);
//999 888
const thenPromise5 = promise1.then(
(res) => {
// console.log(res);
},
(err) => {
throw new Error("竟然报错了");
}
);
thenPromise5.then(
(res) => {
console.log(999, res);
},
(err) => {
console.log(1000, err);
}
);
// 1000 Error: 竟然报错了
// at G:\03.教学视频\0.javascript-王红元\js高级\code\16.promise\6.promise对象的then方法.js:225:11
promise对象的catch方法
promise对象的rejected回调
- 当promise的reject回调调用时,会把当前promise对象状态改为rejected,执行rejected回调,reject执行时的参数会作为rejected的参数传入
- 当executor函数执行中抛出异常时,会把当前promise对象状态改为rejected,执行rejected回调,异常信息会作为rejected的参数传入
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
reject("msg error");
});
});
promise.then(
(res) => {
return "aaa";
},
(err) => {
console.log(err);
}
);
//执行结果:msg error
//当executor函数执行过程中抛出异常,当前promise的状态会变为rejected,rejected回调被调用,异常信息会作为rejected的参数传入
const promise1 = new Promise((resolve, reject) => {
throw new Error("错误信息");
});
promise1.then(
(res) => {
return "aaa";
},
(err) => {
console.log(err);
}
);
// 执行结果:
// Error: 错误信息
// at G:\03.教学视频\0.javascript-王红元\js高级\code\16.promise\7.promise对象的catch方法.js:25:9
// at new Promise (<anonymous>)
// at Object.<anonymous> (G:\03.教学视频\0.javascript-王红元\js高级\code\16.promise\7.promise对象的catch方法.js:24:18)
catch方法
promise1.then(undefined, (err) => {
console.log(err);
});
上面代码可以简写为如下:
promise1.catch((err) => {
console.log(err);
});
catch的特殊性
const promise1 = new Promise((resolve, reject) => {
throw new Error("错误信息");
});
// 1.下面代码,promise1的executor函数执行过程中抛出了异常,promise1.then方法中没有注册rejected回调函数,则执行catch的回调函数
promise1
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
// Error: 错误信息
// at G:\03.教学视频\0.javascript-王红元\js高级\code\16.promise\7.promise对象的catch方法.js:25:9
// at new Promise (<anonymous>)
// at Object.<anonymous> (G:\03.教学视频\0.javascript-王红元\js高级\code\16.promise\7.promise对象的catch方法.js:24:18)
//下面代码,promise2的状态变为了fulfilled,执行了fulfilled函数,
//fulfilled函数中返回的promise对象状态变为了rejected,则promise2.then方法返回的promise对象状态也变成了rejected,则执行catch的回调函数
const promise2 = new Promise((resolve, reject) => {
resolve(111);
});
promise2
.then((res) => {
return new Promise((resolve, reject) => {
reject("报错了");
});
})
.catch((err) => {
console.log(err);
});
拒绝捕获问题
const promise4 = new Promise((resolve, reject) => {
reject("报错了啊啊啊");
});
promise4.then((res) => {
console.log(res);
});
promise4.catch((err) => {
console.log(err);
});
Unhandled promise rejection.关于这个报错问题,意思是没有拒绝捕获回调。应该改为下面
const promise5 = new Promise((resolve, reject) => {
reject("报错了啊啊啊");
});
promise5
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
promise5.catch((err) => {
console.log(err);
});
promise对象的finally方法
- ES9新增的一个特性
- 表示无论promise对象的状态变为fulfilled还是rejected,都会执行finally的回调参数
- finally不接收参数
const promise2 = new Promise((resolve, reject) => {
resolve(111);
});
promise2
.then((res) => {
console.log(res)
})
.catch((err) => {
console.log(err);
})
.finally(() => {
console.log('promise的状态被改变了')
});
// 111
// promise的状态被改变了
Promise类方法-resolve
Promise.resolve的传参处理,遵循promise对象的resolve传参处理
//封装一个方法,可以把一个值转换为promise对象
function toPromise(val) {
return new Promise((resolve, reject) => {
resolve(val);
});
}
const objPromise = toPromise({ name: "lily", age: 18 });
const promise = Promise.resolve(111);
//相当于
const promise1 = new Promise((resolve, reject) => {
resolve(111);
});
Promise类方法-reject
Promise.reject的参数不管是什么类型,都原样传给promise的rejected
const promise = Promise.reject({ name: "lily" });
//相当于
const promise1 = new Promise((resolve, reject) => {
reject({ name: "lily" });
});
//下面为了解决没有捕获拒绝回调的报错
promise.catch((err) => {});
promise1.catch((err) => {});
//Promise.reject的参数不管是什么类型,都原样传给promise的rejected
const promise3 = new Promise((resolve, reject) => {
resolve(111)
});
const promise2 = Promise.reject(promise3);
promise2
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
// Promise { 111 } promise对象被原样输出了
Promise类的all方法
- Promise.all(arr)
- 参数是一个数组
- 数组的元素建议是一个promise对象,如果不是,会使用Promise.resolve把其转为promise对象
- all方法执行返回一个新的promise对象allPromise,
- 当arr中所有的promise对象的状态都变为fulfilled,allPromise对象的状态才会变为fulfilled,执行resolved回调,参数为一个数组,是按照数组中promise对象状态改变的先后顺序,存储每个promise对象的结果
- 一旦arr中有一个promise对象状态变为rejected,allPromise对象的状态就会变为rejected,执行rejected回调,参数为那个第一个被拒的对象的被拒原因
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(111);
}, 100);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(222);
}, 200);
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(333);
}, 300);
});
const promise4 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("error msg");
}, 300);
});
const promise5 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("error error");
}, 300);
});
const allPromise = Promise.all([promise1, promise2, promise3]);
allPromise
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
// [ 111, 222, 333 ]
const allPromise1 = Promise.all([promise1, promise4, promise5]);
allPromise1
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
// error msg
Promise类的allSettled方法
- Promise.allSettled(arr)
- 参数是一个数组
- 数组的元素建议是一个promise对象,如果不是,会使用Promise.resolve把其转为promise对象
- allSettled方法执行返回一个新的promise对象allSettledPromise,
- 当arr中所有的promise对象的状态都敲定后,不管是变为fulfilled还是rejected,allSettledPromise对象的状态都会变为fulfilled,执行resolved回调,
- resolved回调的参数为一个数组,是按照数组中promise对象状态改变的先后顺序,返回每个promise对象的结果,
- 数组中每个元素为一个对象,这个对象有两个属性,status和value/reason
- status为这个promise对象的状态,value为这个对象被对象的结果,reason为被拒绝的原因
- allSettled执行一定返回一个状态为fulfilled的promise的对象
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(111);
}, 100);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(222);
}, 200);
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("error msg");
}, 300);
});
const promise4 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("error error");
}, 400);
});
const promise = Promise.allSettled([promise1, promise2, promise3, promise4]);
promise.then((res) => {
console.log(res);
})
// [
// { status: 'fulfilled', value: 111 },
// { status: 'fulfilled', value: 222 },
// { status: 'rejected', reason: 'error msg' },
// { status: 'rejected', reason: 'error error' }
// ]
Promise类的race方法
- Promise.race(arr)
- 参数是一个数组
- 数组的元素建议是一个promise对象,如果不是,会使用Promise.resolve把其转为promise对象
- race方法执行返回一个新的promise对象racePromise,
- racePromise对象的状态取决于arr中第一个状态被敲定的promise对象firstPromise的状态
- 第一个状态被敲定的promise对象firstPromise的状态变为了fulfilled,racePromise对象的状态都会变为fulfilled,执行resolved回调,
- resolved回调的参数为firstPromise这个对象的resolve值,
- 第一个状态被敲定的promise对象firstPromise的状态变为了rejected,racePromise对象的状态都会变为rejected,执行rejected回调,
- rejected回调的参数为firstPromise这个对象的reject值,
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(111);
}, 100);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(222);
}, 200);
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("error msg");
}, 300);
});
const promise4 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("error error");
}, 400);
});
const promise = Promise.race([promise1, promise2, promise3, promise4]);
promise
.then((res) => {
console.log("res", res);
})
.catch((err) => {
console.log("err", err);
});
//err 111
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(111);
}, 100);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(222);
}, 200);
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("error msg");
}, 300);
});
const promise4 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("error error");
}, 400);
});
const promise = Promise.race([promise1, promise2, promise3, promise4]);
promise
.then((res) => {
console.log("res", res);
})
.catch((err) => {
console.log("err", err);
});
//res 111
Promise类的any方法
- Promise.any(arr)
- 参数是一个数组
- 数组的元素建议是一个promise对象,如果不是,会使用Promise.resolve把其转为promise对象
- any方法执行返回一个新的promise对象anyPromise,
- 只要arr中一个的promise对象的状态变为了fulfilled,anyPromise对象的状态都会变为fulfilled,执行resolved回调,
- resolved回调的参数为状态首先变为fulfilled的promise对象的resolve值,
- 如果数组中所有的promise对象最终都变为rejected,anyPromise对象的状态都会变为rejected,执行rejected回调,
- rejected回调的参数为一个合计错误aggregateError,可以通过aggregateError.errors获得一个存储着所有promise被拒原因的数组
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(111);
}, 100);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(222);
}, 200);
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("error msg");
}, 300);
});
const promise4 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("error error");
}, 400);
});
const promise = Promise.any([promise1, promise2, promise3, promise4]);
promise
.then((res) => {
console.log("res", res);
})
.catch((err) => {
console.log("err", err);
});
//res 111
const promise11 = Promise.any([promise3, promise4]);
promise11
.then((res) => {
console.log("res", res);
})
.catch((err) => {
console.log("err", err);
console.log('err', err.errors)
});
// err [AggregateError: All promises were rejected]
// err [ 'error msg', 'error error' ]
非常感谢王红元老师的深入JavaScript高级语法让我学习到很多 JavaScript
的知识
网友评论