一文教你搞定 Promise

ES6 入门第五章

Promise

Promise 是什么?

Promise 是 ES6 引入的异步编程的新解决方案(旧的是谁?旧的解决方案是纯回调函数)。语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。

用来封装异步操作并可以获取其成功或失败的结果。

Promise的特点

(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected

Promise 的状态改变

1)pending 变成 fulfilled

2)pending 变成 rejected

说明:只有这两种状态改变情况,且一个Promise对象只能改变一次状态

​ 无论变成成功还是失败,都会有一个结果数据

​ 成功的结果数据一般称为 value ,失败的结果数据一般称为 reason

Promise缺点

  1. 无法取消Promise,一旦新建它就会立即执行,无法中途取消。

  2. 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。

  3. 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

Promise 的基本流程

在这里插入图片描述

Promise基本使用

步骤:

  1. 创建一个新的Promise对象
  2. 执行异步操作任务
  3. 1 如果成功了,调用resolve(value)
    2. 如果失败了,调用reject(reason)
//1. 创建一个新的Promise对象
const p = new Promise((resolve,reject) => {//执行器函数
	//2.执行异步操作任务
	setTimeout(() => {
		const time = Date.now() //如果当前时间是偶数就代表成功,否则代表失败
		if(time % 2 == 0 ){	//3.1如果成功了,调用resolve(value)
			resolve('成功的数据,time=' + time)
		} else {  //3.2如果失败了,调用reject(reason)
			reject('失败的数据,time=' + time)
		}
	},1000)
				
})
			
p.then(
	value => { //接收得到成功的value数据   onResolved
		console.log('成功的回调',value)
	},
	reason => { //接收得到失败的reason数据  onRejected
		console.log('失败的回调',reason)
	}
)

在这里插入图片描述
在这里插入图片描述

为什么要用 Promise?

  1. 指定回调函数的方式更加灵活(灵活指的是时间的问题)
    1) 旧的:必须在启动异步任务前指定
    2)Promise:启动异步任务 => 返回 Promise 对象 => 给 Promise 对象绑定回调函数(甚至可以在异步任务结束后指定多个)

例子:创建一个音频文件

//成功的回调函数
function successCallback(result){
	console.log("声音文件创建成功:" + result);
}
//失败的回调函数
function failureCallback(result){
	console.log("声音文件创建失败:" + error);
}

1)使用纯回调函数

//1. 使用纯回调函数
creatAudioFileAsync(audioSettings, successCallback, failureCallback)
			

2)使用Promise

const promise = createAudioFileAsync(audioSettings);
setTimeout(()=> {
	promise.then(successCallback, failureCallback);
},3000)
  1. 支持链式调用,可以解决回调地狱问题

  2. 什么是回调地狱?

    回调函数嵌套调用(多个串联的异步操作:第一个执行完,再执行第二个……),外部回调函数异步执行的 结果是嵌套的回调执行的条件

    //回调地狱
    doSomething(function(result){
    	doSomethingElse(result,function(newResult){
    		doThirdThing(newResult,function(finalResult){
    			console.log('Got the final result:' + finalResult)
    		},failureCallback)
    	},failureCallback)
    },failureCallback)
    
  3. 回调地狱的缺点?

    不便于阅读

    不便于异常处理

  4. 解决方案

    Promise链式调用

    //使用Promise的链式调用解决回调地狱
    doSomething()
    .then(function(result){
    	return doSomethingElse(result)
    })
    .then(function(newResult){
    	return doThirdThing(newResult)
    })
    .then(function(finalResult){
    	console.log('Got the final result:' + finalResult)
    })
    .catch(failureCallback)
    
  5. 终极解决方案

    async/await

    // async/await:回调地狱的终极解决方案
    async function request() {
    	try{
    		const result = await doSomething()
    		const newResult = await doSomethingElse(result)
    		const finalResult = await doThirdThing(newResult)
    		console.log('Got the final result:' + finalResult)
    	} catch(error) {
    		failureCallback(error)
    	}
    }
    

如何使用 Promise

  1. Promise构造函数:Promise(excutor){}

    1)excutor 函数:执行器 (resolve,reject) => {}

    2)resolve 函数:内部定义成功时,我们调用的函数 value => {}

    3)reject函数:内部定义失败时,我们调用的函数 reason => {}

    说明:excutor 会在 Promise 内部立即同步回调,异步操作在执行器中执行

原型方法

​ 1)Promise.prototype.then 方法

​ 2)Promise.prototype.catch 方法

​ 3)Promise.prototype.finally 方法

自身的方法

all()、race()、reject()、resolve()、try()

  1. Promise.prototype.then 方法 (onResolved, onRejected) => {}

    ​ onResolved函数:成功的回调函数 (value) => {}

    ​ onRejected函数:失败的回调函数 (reason) => {}

    ​ 说明:指定用于得到成功value 的成功回调和用于得到失败reason的失败回调

    ​ 返回一个新的Promise对象

    new Promise((resolve, reject) => {
    	setTimeout(() => {
    		resolve("成功的数据")
    		//reject("失败的数据")
    	},1000)
    	}).then(
    		value => {
    			console.log('onResolved()1',value)
    		}
    	).catch(
    		reason => {
    			console.log('onRejected()1',reason)
    		}
    	)
    

在这里插入图片描述
3. Promise.prototype.catch 方法 (onRejected)=> {}

​ onRejected函数:失败的回调函数 (reason) => {}

​ 说明:then()的语法糖,相当于:then(undefined, onRejected) 或 then(null, onRejected)

new Promise((resolve, reject) => {
	setTimeout(() => {
		//resolve("成功的数据")
		reject("失败的数据")
	},1000)
	}).then(
		value => {
			console.log('onResolved()1',value)
		}
	).catch(
		reason => {
			console.log('onRejected()1',reason)
		}
	)

在这里插入图片描述
4. Promise.prototype.finally 方法

用于指定不管 Promise 对象最后状态如何,都会执行的操作。

  1. Promise.resolve 方法 : (value) => {}

​ value:成功的数据或Promise对象

​ 作用:将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去 。

​ 说明:返回一个成功/失败的Promise对象

//产生;一个成功值为1的promise对象
const p1 = new Promise((resolve,reject) => {
	resolve(1)
})
//语法糖:就是简介语法
const p2 = Promise.resolve(2)
console.log(p1)
console.log(p2)

在这里插入图片描述
6. Promise.reject 方法:(reason) => {}

reason:失败的原因

​ 作用:将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

​ 说明:返回一个失败的Promise对象

//产生;一个失败值为3的promise对象
const p3 = new Promise((resolve,reject) => {
				reject(3)
})
const p4 = Promise.reject(3)
console.log('p3:',p3)
console.log('p4:',p4)

在这里插入图片描述

//产生;一个成功值为1的promise对象
const p1 = new Promise((resolve,reject) => {
	resolve(1)
})
//语法糖:就是简介语法
const p2 = Promise.resolve(2)
console.log('p1:',p1)
console.log('p2:',p2)
const p3 = new Promise((resolve,reject) => {
	reject(3)
})
const p4 = Promise.reject(3)
console.log('p3:',p3)
console.log('p4:',p4)
p1.then(value => {console.log(value)})
p2.then(value => {console.log(value)})
p3.then(null,reason => {console.log(reason)})
p4.catch(reason => {console.log(reason)})

在这里插入图片描述
7. Promise.all 方法:(promises) => {}

promises:包含n个promise的数组

​ 说明:返回一个新的promise,只有所有的promise都成功才成功,只要有一个失败了就直接失败

const p = Promise.all([p1, p2, p3]);

上面代码中,Promise.all()方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。

p的状态由p1p2p3决定,分成两种情况。

(1)只有p1p2p3的状态都变成fulfilledp的状态才会变成fulfilled,此时p1p2p3的返回值组成一个数组,传递给p的回调函数。

(2)只要p1p2p3之中有一个被rejectedp的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

const p1 = new Promise((resolve,reject) => {
				resolve(1)
})
const p2 = Promise.resolve(2)
const p3 = Promise.reject(3)
const pAll = Promise.all([p1,p2])
console.log('pAll:',pAll)
pAll.then(
	value => {
		console.log('all onResolved()',value)
	},
	reason => {
		console.log('all onRejected()',reason)
	}
)

在这里插入图片描述

const p1 = new Promise((resolve,reject) => {
				resolve(1)
})
const p2 = Promise.resolve(2)
const p3 = Promise.reject(3)
//const pAll = Promise.all([p1,p2])
const pAll = Promise.all([p1,p2,p3])
console.log('pAll:',pAll)
pAll.then(
	value => {
		console.log('all onResolved()',value)
	},
	reason => {
		console.log('all onRejected()',reason)
	}
)

在这里插入图片描述
8. Promise.race 方法 (promises) => {}

promises:包含n个promise的数组

说明:返回一个新的promise,第一个完成的promise的结果状态就是最终的结果状态

const p = Promise.race([p1, p2, p3]);

上面代码中,只要p1p2p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

const p1 = new Promise((resolve,reject) => {
				resolve(1)
})
const p2 = Promise.resolve(2)
const p3 = Promise.reject(3)
const pRace = Promise.race([p1,p2,p3])

console.log('pRace',pRace)
pRace.then(
	value => {
		console.log('race onResolved()',value)
	},
	reason => {
		console.log('race onRejected()',reason)
	}
)

在这里插入图片描述

const p1 = new Promise((resolve,reject) => {
				resolve(1)
})
const p2 = Promise.resolve(2)
const p3 = Promise.reject(3)
//const pRace = Promise.race([p1,p2,p3])
const pRace = Promise.race([p3,p1,p2])
console.log('pRace',pRace)
pRace.then(
	value => {
		console.log('race onResolved()',value)
	},
	reason => {
		console.log('race onRejected()',reason)
	}
)

在这里插入图片描述
状态也不一定是由第一个决定,要看谁先完成,状态就为谁的状态

const p1 = new Promise((resolve,reject) => {
			setTimeout(() => {
				resolve(1)
			},100)	
		})
const p2 = Promise.resolve(2)
const p3 = Promise.reject(3)
const pRace = Promise.race([p1,p2,p3])
console.log('pRace',pRace)
pRace.then(
	value => {
		console.log('race onResolved()',value)
	},
	reason => {
		console.log('race onRejected()',reason)
	}
)

在这里插入图片描述

Promise的几大关键问题
  1. 如何改变Promise的状态?

    (1)resolve(value):如果当前是 pending 就会变成 fulfilled

    (2)reject(reason):如果当前是 pending 就会变成 rejected

    (3)抛出异常:如果当前是 pending 就会变成 rejected

    const p = new Promise((resolve,reject) => {
    //resolve(1) //Promise变成 fulfilled 成功状态
    //reject(2) //Promise变成  rejected 失败状态
    //throw new Error('出错了') //抛出异常,promise变为rejected失败状态,reason为 抛出的error
    throw 3 //抛出异常,promise变为rejected失败状态,reason为 抛出的3
    })
    p.then(
    	value => {},
    	reason => {console.log('reason',reason)}
    )
    

在这里插入图片描述
一个 Promise 指定多个成功/失败回调函数,都会调用吗?

当 Promise 改变为对应状态时都会调用

const p = new Promise((resolve,reject) => {
//resolve(1) //Promise变成 fulfilled 成功状态
//reject(2) //Promise变成  rejected 失败状态
//throw new Error('出错了') //抛出异常,promise变为rejected失败状态,reason为 抛出的error
throw 3 //抛出异常,promise变为rejected失败状态,reason为 抛出的3
})
p.then(
	value => {},
	reason => {console.log('reason',reason)}
)
p.then(
	value => {},
	reason => {console.log('reason2',reason)}
)

在这里插入图片描述

  1. 改变 Promise 状态和指定回调函数谁先谁后?

    (1)都有可能,正常情况下是先指定回调再改变状态,但也可以先改状态再指定回调

    (2)如何先改状态再指定回调?

    ​ 1)在执行器中直接调用 resolve()/reject()

    ​ 2)延迟更长时间才调用 then()

    (3)什么时候才能得到数据?

    ​ 1)如果先指定的回调,那当状态发生改变时,回调函数就会调用,得到数据

    ​ 2)如果先改变的状态,那当指定回调时,回调函数就会调用,得到数据

    //常规:先指定回调函数,后改变的状态
    new Promise((resolve,reject) => {
    	setTimeout(() => {
    		resolve(1) //后改变的状态(同时指定数据),异步执行回调函数
    	},1000)
    }).then(//先指定回调函数,保存当前指定的回调函数
    	value => {console.log('value',value)},
    	reason => {console.log('reason',reason)}
    )
    		
            
    /*++++++++++++++++++++++++*/
    //如何先改状态,后指定回调函数
    new Promise((resolve,reject) => {
    	resolve(1) //先改变的状态(同时指定数据)
    }).then(//后指定回调函数,异步执行回调函数
    	value => {console.log('value2',value)},
    	reason => {console.log('reason2',reason)}
    )
    			
    /*++++++++++++++++++++++++*/
    const p = new Promise((resolve,reject) => {
    	setTimeout(() => {
    		resolve(1) //先改变的状态(同时指定数据),异步执行回调函数
    	},1000)
    })
    setTimeout(() => {
    	p.then(
    		value => {console.log('value3',value)},
    		reason => {console.log('reason3',reason)}
    	)
    },1100)
    
  2. Promise.then()返回的新的Promise的结果状态由什么决定?

    (1)简单表达:由then()指定的回调函数执行的结果决定

    (2)详细表达

    ​ 1)如果抛出异常,新的Promise 变为rejected,reason 为抛出的异常

    ​ 2)如果返回的是非 Promise的任意值,新的Promise变为resolved,value为返回的值

    ​ 3)如果返回的是另一个新的Promise,此Promise的结果就会成为新的Promise的结果

    new Promise((resolve,reject) =>{
    	resolve(1)
    }).then(
    	value => {
    		console.log('onResolved1()',value)
    	},
    	reason => {
    		console.log('onRejected1()',reason)
    	}).then(
    		value => {
    			console.log('onResolved2()',value)
    		},
    		reason => {
    			console.log('onRejected2()',reason)
    		}
    )
    

在这里插入图片描述

new Promise((resolve,reject) =>{
	resolve(1)
	//reject(1)
}).then(
	value => {
		console.log('onResolved1()',value)
//		return 2
//		return Promise.resolve(3)
		return Promise.reject(5)
	},
	reason => {
		console.log('onRejected1()',reason)
	}).then(
		value => {
			console.log('onResolved2()',value)
		},
		reason => {
			console.log('onRejected2()',reason)
		}
)

在这里插入图片描述
5. Promise如何串连多个操作任务?

(1)Promise 的then()返回一个新的 Promise,可以开成then()的链式调用

(2)通过then的链式调用串连多个同步/异步任务

new Promise((resolve,reject) =>{
	setTimeout(() => {
		console.log("执行任务1(异步)")
		resolve(1)
	},1000)
}).then(
	value => {
	console.log('任务1的结果:',value)
	console.log('执行任务2(同步)')
	return 2
	}
).then(
	value => {
	console.log('任务2的结果:',value)
	return new Promise((resolve,reject) => {
	//启动异步任务3(异步)
	setTimeout(() => {
		console.log('执行任务3(异步)')
		resolve(3)
	},1000)
	})
}
).then(
	value => {
	console.log('任务3的结果:',value)
	}
)

在这里插入图片描述
Promise异常传/穿透?

(1)当使用Promise的then链式调用时,可以在最后指定失败的回调

(2)前面任何操作出了异常,都会传到最后失败的回调中处理

new Promise((resolve,reject) =>{
				//resolve(1)
				reject(1)
			}).then(
				value => {
					console.log('onResolved1()',value)
					return 2
				},
				//reason => {throw reason}
			).then(
				value => {
					console.log('onResolved2()',value)
					return 3
				},
				//reason => {throw reason}
			).then(
				value => {
					console.log('onResolved3()',value)
				},
				reason => Promise.reject(reason)
			).catch(reason => {
				console.log('onRejected1()',reason)
			})

执行reject(1)这个函数,因为第一个then()里面没有reason函数,其实默认为reason => {throw reason},所以会一直往下,然后到第二个then(),第二个也没有reason函数,所有到第三个then(),第三个也没有,所有到最后的catch,这就是传/穿透。
在这里插入图片描述
6. 中断Promise链?

(1)当使用Promise的then链式调用时,在中间中断,不再调用后面的回调函数

(2)办法:在回调函数中返回一个pending状态的Promise对象

new Promise((resolve,reject) =>{
				//resolve(1)
				reject(1)
			}).then(
				value => {
					console.log('onResolved1()',value)
					return 2
				},
				//reason => {throw reason}
			).then(
				value => {
					console.log('onResolved2()',value)
					return 3
				},
				reason => {throw reason}
			).then(
				value => {
					console.log('onResolved3()',value)
				},
				reason => Promise.reject(reason)
			).catch(reason => {
				console.log('onRejected1()',reason)
				//throw reason
				//return Promise.reject(reason)
				return new Promise(() => {})//返回一个pending的Promise 中断Promise链
			}).then(
				value => {
					console.log('onResolved3()',value)
				},
				reason => {
					console.log('onRejected2()',reason)
				}
			)

在这里插入图片描述
如果不想执行catch后面的then了,则用 return new Promise(() => {})中断Promise链,因为此时的状态为pending,既不是fulfilled状态也不是rejected。

async 与 await

async 函数

  1. 函数的返回值为Promise对象
  2. Promise对象的结果由async函数执行的返回值决定
// async 函数的返回值是一个Promise对象
async function fn1() {
	return 1
}

const result = fn1()
console.log(result)

在这里插入图片描述
await 表达式

  1. await 右侧的表达式一般为 Promise对象,但也可以是其它的值
  2. 如果表达式是Promise对象,await返回的是Promise成功的值
  3. 如果表达式是其它值,直接将此值作为await的返回值
function fn2() {
	return new Promise((resolve,reject) => {
		setTimeout(() => {
			resolve(5)
		},1000)
	})
}
async function fn3() {
	const value = await fn2() //await右侧表达式为Promise,得到的结果就是Promise成功的value
	console.log('value',value)
}
fn3()

在这里插入图片描述

function fn5() {
	return 9
}
async function fn3() {
	//const value = await fn2() //await右侧表达式为Promise,得到的结果就是Promise成功的value
	  const value = await fn5() //await右侧表达式不是Promise,得到的结果就是它本身
		console.log('value',value)
}
fn3()

在这里插入图片描述
注意:

  1. await必须写在async函数中,但async函数中可以没有await
  2. 如果await的Promise失败了,就会抛出异常,需要通过try…catch来捕获处理
function fn2() {
	return new Promise((resolve,reject) => {
		setTimeout(() => {
			//resolve(5)
			  reject(6)
		},1000)
	})
}
async function fn3() {
	try{
		const value = await fn2()
		console.log('value',value)
	} catch (error) {
		console.log('得到失败的结果',error)
	}
}
fn3()

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值