1是什么?
- 抽象表达:JS中解决异步编程的新的解决方案(原先异步编程的解决方式是使用回调函数,回调函数本身没有问题,问题是多个回调函数嵌套,容易形成回调地狱,Promise就是为了解决这个问题)
- 具体表达
- 语法上,Promise是一个构造函数,用来生成Promise实例对象。
- 功能上,promise对象用来封装一个异步操作并可以获取其结果(成功、失败)进行相应的处理。
2为什么使用Promise?
-
指定回调函数的方式更加灵活
- 旧的:必须在启动异步任务之前指定
- promise:启动异步任务、返回promise对象、给promise对象绑定回调函数
-
支持链式调用,解决回调地狱问题
- 回调地狱:回调函数嵌套调用,外部回调函数的执行结果是嵌套的回调执行的条件
- 回调地狱的缺点:不便于阅读、不便于异常处理
6.3三种状态
pending、resolved、rejected
- pending:可以转换为其他两个状态,一旦转换成这两种状态就不再改变了。(只有这两种状态改变,并且一个promise对象只能改变一次)
- resolve:将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果value,作为参数传递出去;
- reject:将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误的原因reason,作为参数传递出去。
- resolve 和 reject 的作用域只有起始函数,不包括 then 以及其他序列;resolve 和 reject 并不能够使起始函数停止运行,别忘了 return。
- 抛出错误也能将promise从pending状态改为rejected
6.4基本使用
- Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数。在异步操作成功时调用resolve函数,失败时调用reject函数。
- then方法:分别指定resolved状态和rejected状态的回调函数。
- 第一个回调函数参数当promise对象的状态变为resolved时调用,可以拿到resolve()传过来的值value
- 第二个回调函数参数当promise对象的状态变为rejected时调用,可以拿到reject()传过来的原因reason,可选的
- 可以链式调用,前一个then()方法中的回调函数中又可能返回一个promise实例,这时候后面一个then()方法中的回调函数会等前一个promise实例的状态发生变化才会调用。
- 如果我们的后续任务是异步任务的话,必须return 一个新的 promise 对象。如果后续任务是同步任务,只需 return 一个结果即可。
// 创建一个promise实例p
const p = new Promise((resolve, reject) => {
setTimeout(() => {
const time = Date.now();
if(time % 2 == 0){
resolve('成功,time='+time)
}else{
reject('失败,time='+time)
}
}, 1000);
})
p.then(value=>{
console.log('成功的回调', value);
},reason=>{
console.log('失败的回调', reason);
})
6.5API
(1)Promise构造函数
- excutor函数:执行器(resolve,reject)=>{}
- resolve函数:内部定义成功时我们调用的函数resolve(成功的结果)
- reject函数:内部定义失败时我们调用的函数reject(失败的原因)
注意:excutor会在Promise内部立即同步调用
(2)Promise.prototype.then(onResolved,onRejected)
- onResolved函数,成功的回调函数,value=>{}
- onRejected函数,失败的回调函数,reason=>{}
- 返回一个新的promise对象
(3)Promise.prototype.catch
- 用于指定发生错误时的回调
- 是Promise.prototype.then(undefined,onRejected)方法的别名
- 接收一个函数参数,这个函数的参数是promise失败的原因
(4)Promise.resolve
- value=>{}
- value:成功的数据或promise对象
- 返回一个成功/失败的promise对象
// 如果传入的参数为非Promise类型的对象,则返回的结果为成功的Promise对象
let p1 = Promise.resolve(111);
console.log(p1); // Promise {<fulfilled>: 111}
// 如果传入的参数为Promise对象,则参数的结果决定了resolve的结果
let p2 = Promise.resolve(new Promise((resolve, reject)=>{
resolve("OK")
}))
console.log(p2); // Promise {<fulfilled>: "OK"}
let p3 = Promise.resolve(new Promise((resolve, reject)=>{
reject("error");
}))
p3.catch(reason=>{
console.log(reason);
})
console.log(p3); // Promise {<rejected>: "error"}
(5)Promise.reject
- reason=>{}
- 返回一个失败的promise对象
// Promise.reject, 不管参数是什么,返回一个失败的Promise
let p4 = Promise.reject(111);
console.log(p4); //Promise {<rejected>: 111}
let p5 = Promise.reject(new Promise((resolve, reject)=>{
resolve();
}))
console.log(p5); //Promise {<rejected>: Promise}
(6)Promise.all
- (promises)=>{},promises包含n个promise的数组
- 多个 Promise 任务同时执行。如果全部成功执行,则以数组的方式返回所有 Promise 任务的执行结果。 如果有一个 Promise 任务 rejected,则只返回 rejected 任务的结果(如果多个任务失败,返回第一个任务失败的结果)。
//当所有的promise都成功
let p1 = new Promise((resolve, reject)=>{
resolve('ok');
})
let p2 = Promise.resolve(111);
let p3 = Promise.resolve(222);
let result = Promise.all([p1, p2, p3]);
console.log(result);
// Promise {<pending>}
// [[Prototype]]: Promise
// [[PromiseState]]: "fulfilled"
// [[PromiseResult]]: Array(3)
// 0: "ok"
// 1: 111
// 2: 222
// 当有promise失败
let p1 = new Promise((resolve, reject)=>{
resolve('ok');
})
let p2 = Promise.reject(111);
let p3 = Promise.resolve(222);
let result = Promise.all([p1, p2, p3]);
//Promise {<pending>}
// [[Prototype]]: Promise
// [[PromiseState]]: "rejected"
// [[PromiseResult]]: 111
(7)Promise.race
- (promises)=>{},promises包含n个promise的数组
- 多个 Promise 任务同时执行,返回最先执行结束的 Promise 任务的结果,不管这个 Promise 结果是成功还是失败。
let p1 = new Promise((resolve, reject)=>{
setTimeout(() => {
resolve('ok');
}, 1000);
})
let p2 = Promise.resolve(111);
let p3 = Promise.resolve(222);
let result = Promise.race([p1, p2, p3]);
console.log(result);// 最先执行结束的是p2
// Promise {<pending>}
// [[Prototype]]: Promise
// [[PromiseState]]: "fulfilled"
// [[PromiseResult]]: 111
(8)finally()方法
- 用于指定不管 Promise 对象最后状态如何,都会执行的操作。
(9)any()方法
- 接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例返回。
- 只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。
6.6异常穿透与中断链式调用
(1)异常穿透
- 当你使用Promise的then,进行链式调用的时候,可以在最后指定失败的回调
- 前面任何操作出现了异常,都会传递到最后失败的回调中进行处理
(2)中断链式调用
- 有且只有一种方式,返回一个pending状态的promise,return new Promise(()=>{})
- 后面的then就不会执行
6.7手写Promise(*****)
class Promise{
constructor(excutor){
// 初始状态
this.promiseState = 'pending';
// 结果
this.promiseResult = null;
this.callback = [];
const that = this;
function resolve(data){
//这里面的this指向的是window,拿外面的this保存在that中
if(that.promiseState !== 'pending') return;
that.promiseState = 'fulfilled';
that.promiseResult = data;
//执行成功的回调函数,回调函数不止一个,遍历
that.callback.forEach((item)=>{
setTimeOut(()=>{
item.onResolved(data);
})
})
}
function reject(data){
if(that.promiseState !== 'pending') return;
that.promiseState = 'rejected';
that.promiseResult = data;
//执行失败的回调函数
that.callback.forEach((item)=>{
setTimeout(() => {
item.onRejected(data);
});
})
}
try{
// 同步调用执行器函数,并接受参数
excutor(resolve, reject);
}catch(e){
reject(e);
}
}
then(onResolved,onRejected){
if(typeof onRejected !== 'function'){
onRejected = reason => {
throw reason;
}
}
if(typeof onResolved !== 'function'){
onResolved = value => value;
}
return new Promise((resolve, reject)=>{
// 封装回调函数
const callback = (type) =>{
try {
let result = type(this.promiseResult);
if(result instanceof Promise){
result.then(v=>{
resolve(v);
},r=>{
reject(r);
})
}else{
resolve(result);
}
} catch (error) {
reject(error);
}
}
if(this.promiseState === 'fulfilled'){
setTimeout(()=>{
callback(onResolved);
})
}
if(this.promiseState === 'rejected'){
setTimeout(()=>{
callback(onRejected);
})
}
if(this.promiseState === 'pending'){
// 使用数组保存回调函数,避免覆盖前面的回调函数
this.callback.push({
onResolved: ()=>{
callback(onResolved);
},
onRejected: ()=>{
callback(onRejected);
}
});
}
})
}
catch(onRejected){
return this.then(undefined, onRejected);
}
static resolve(value){
return new Promise((resolve, reject)=>{
if(value instanceof Promise){
value.then(v=>{
resolve(v);
}, r=>{
reject(r);
})
}else{
resolve(value);
}
})
}
static reject(value){
return new Promise((resolve, reject)=>{
reject(value);
})
}
static all(promises){
return new Promise((resolve, reject)=>{
let count = 0;
let arr = [];
for(let i = 0; i< promises.length;i++){
promises[i].then(v=>{
count++;
arr[i] = v;
if(count === promises.length){
resolve(arr);
}
}, r=>{
reject(r)
})
}
})
}
static race(promises){
return new Promise((resolve, reject)=>{
for(let i=0; i<promises.length;i++){
promises[i].then(v=>{
resolve(v);
}, r=>{
reject(r);
})
}
})
}
}