Promise
1.基本结构:
const promise = new Promise(handler)
handler:(resolve, reject) => {}
promise.then(onFulfilled, onRejected).then(onFulfilled, onRejected)
2.状态:
promise存在三种状态
-
pending
-
fulfilled
-
rejected
状态只能由 Pending
变为 Fulfilled
或由 Pending
变为 Rejected
,且状态改变之后不会在发生变化,会一直保持这个状态。
handler
函数包含 resolve
和 reject
两个参数,它们是两个函数,可以用于改变 Promise
的状态和传入 Promise
的值
3.构思源码需要注意的点:
对于handler:handler必须是函数 需要做类型判断 非函数类型则抛出错误
对于resolve和reject:需要做两件事,一个是状态修改,另一个是值的传递,另外需要注意确保函数只能执行一次
resolve(val) {
if(this.status !== 'PENDING') return // 确保只能执行一次
this.status = 'FULFILLED' // 状态修改
this.value = val // 收集传进来的值
}
reject(err) {
if(this.status !== 'PENDING') return
this.status = 'REJECTED'
this.value = err
}
对于then以及其参数onFulfilled和onRejected:
-
当resolve或reject执行后状态发生了改变才会执行then以及内部对应的onFulfilled或者onRejected
-
需要注意onFulfilled和onRejected必须是函数 否则会被忽略
-
then()会返回一个promise 这个是链式调用的基础
-
then中的onFulfilled或者onRejected需要有返回值 才能使得 下一个then中的onFulfilled或者onRejected的参数有值,没有返回值则为undefined
-
如果onFulfilled或者onRejected有返回值
-
如果返回值不是Promise :下一个promise的then会立即执行(状态为fulfilled)返回的值作为这个then里面onFulfilled或者onRejected的参数
let promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve() }, 1000) }) promise2 = promise1.then(res => { console.log('promise1的状态变为fulfilled') // 1s后执行 return '这是给promise2的' }) promise2.then(res => { console.log(res) // 打印 这是给promise2的 在promise1的then执行完会立即执行 })
-
如果返回值是Promise:该返回的promise相当于下一个promise,下一个promise的then会在该返回值的state变化后执行,then中onFulfilled或者onRejected的参数也是返回的promise中进行传递的
let promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve("这是传给promise1的"); }, 1000); }); let promise2 = promise1.then((res) => { console.log(res, "promise1的回调执行拉"); // 1s后执行 return new Promise((resolve, reject) => { setTimeout(() => { resolve("这是传给promise2的"); }, 2000); }); }); promise2.then((res) => { console.log(res, "promise2的回调执行拉"); // 在promise1的then执行完2s后执行 打印 这是传给promise2的, promise2的回调执行拉 });
-
4.简易版Promise
class MyPromise{
const isFunction = variable => typeof variable === 'function'
constructor(handler) {
// handler必须是函数 否则抛错
if (!isFunction(handle)) {
throw new Error('MyPromise must accept a function as a parameter')
}
// 首先声明变量用来存储状态以及传递的值
this.status = 'PENDING'
this.resolveValue = undefined
this.rejectValue = undefined
// 这两个数组后面解释其作用
this.onFulfilledList = []
this.onRejectedList = []
// 定义resolve以及reject
resolve(val) {
if(this.status !== 'PENDING') return // 确保只能执行一次resolve或者reject
this.status = 'FULFILLED' // 状态修改
this.resolveValue = val // 收集传进来的值
}
reject(err) {
if(this.status !== 'PENDING') return
this.status = 'REJECTED'
this.rejectValue = err
}
// 执行handler
try{
/*
* 注意:易错点 这里必须通过bind对resolve和reject的this绑定为此promise实例
* 否则在resolve和reject内部无法通过this获取到此promise实例的status和resolveValue/rejectValue
*/
handler(this.resolve.bind(this), this.reject.bind(this))
}catch(err){
this.reject(err)
}
}
}
// 定义then
MyPromise.prototype.then(onFulfilled, onRejected) {
switch(this.status){
case 'FULFILLED':{
onFulfilled(this.resolveValue)
}
case 'REJECTED':{
onRejected(this.rejectValue)
}
}
}
5.then的完善
上诉简易版只是最基本的promise雏形,下面将对其进行完善
完善点1:
如果handler中的resolve或者reject函数被包裹在异步方法中,会出现先执行then后执行resolve或者reject的情况(此时状态还是pending,所以then中的回调均不会执行)
修正如下:
// 新增两个变量用来存储回调函数
this.onFulfilledList = []
this.onRejectedList = []
// then的修正
MyPromise.prototype.then(onFulfilled, onRejected) {
switch(this.status){
case 'FULFILLED':{
onFulfilled(this.resolveValue)
break
}
case 'REJECTED':{
onRejected(this.rejectValue)
break
}
// 将回调都存储到回调数组里面
case 'PENDING': {
this.onFulfilledList.push(() => {
onFulfilled(this.resolveValue)
})
this.onRejectedList.push(() => {
onRejected(this.rejectValue)
})
}
}
}
// resolve和reject的修正
resolve(val) {
if(this.status !== 'PENDING') return // 确保只能执行一次resolve或者reject
this.status = 'FULFILLED' // 状态修改
this.resolveValue = val // 收集传进来的值
// 执行回调
this.onFulfilledList.forEach((cb) => {
cb()
})
}
reject(err) {
if(this.status !== 'PENDING') return
this.status = 'REJECTED'
this.rejectValue = err
// 执行回调
this.onRejectedList.forEach((cb) => {
cb()
})
}
完善点2:
完成then的链式调用,对应上面then需要注意的2、3、4、5点
MyPromise.prototype.then(onFulfilled, onRejected) {
// 对应第3点返回新的promise实例以实现链式调用
return promise2 = new MyPromise((resolve, reject) => {
// 需要注意 修正后的回调不仅会执行自己promise的回调 还会干预所返回的promise的状态
// 修正后的成功回调
fixedOnfulfilled(value) {
// 执行自己promise的回调看是否报错 如果报错直接修改下一个promise的状态为rejected
try {
// 判断自己promise的回调是否为函数 不是函数直接传递值给下一个promise(对应第2点)
if(!isFunction(onFulfilled)) {
resolve(value)
}else {
let res = onFulfilled(value) // 执行自己的回调并收集返回值
// 判断返回值是否为promise 对应第5点
if(res instanceof MyPromise) {
// 返回值是promise
// 这里不太好理解 实际是相当于将下一个promise的resolve和reject当作返回promise(res)的回调 执行返回promise回调的同时 修改下一个promise的状态 具体传递的值 是由返回promise内部决定的
res.then((v) => {resolve(v)}, (err) => {reject(err)}
}else{
// 返回值不是promise
resolve(res)
}
}
}catch(err) {
// 修改下一个promise的状态为rejected
reject(err)
}
}
// 修正后的失败回调
fixedOnRejected(err) {
// 执行自己promise的回调看是否报错 如果报错直接修改下一个promise的状态为rejected
try {
// 判断自己promise的回调是否为函数 不是函数直接传递值给下一个promise(对应第2点)
if(!isFunction(onRejected)) {
reject(err)
}else {
let res = onRejected(err) // 执行自己的回调并收集返回值
// 判断返回值是否为promise 对应第5点
if(res instanceof MyPromise) {
// 返回值是promise
// 这里不太好理解 实际是相当于将下一个promise的resolve和reject当作返回promise(res)的回调 执行返回promise回调的同时 修改下一个promise的状态 具体传递的值 是由返回promise内部决定的
res.then((v) => {resolve(v)}, (err) => {reject(err)}
}else{
// 返回值不是promise
reject(err)
}
}
}catch(err) {
// 修改下一个promise的状态为rejected
reject(err)
}
}
// 根据状态执行修正后的回调
switch(this.status){
case 'fulfilled':{
fixedOnfulfilled(this.resolveValue)
break
}
case 'rejected':{
fixedOnRejected(this.rejectValue)
break
}
// 将回调都存储起来
case 'pending': {
this.onFulfilledList.push(() => {
fixedOnfulfilled(this.resolveValue)
})
this.onRejectedList.push(() => {
fixedOnRejected(this.rejectValue)
})
}
}
})
}
完善点3:
异步修正
then中回调函数中是以异步的方式执行的
switch(this.status){
case 'FULFILLED':{
// 将成功回调放入事件队列中
setTimeOut(() => {
fixedOnfulfilled(this.resolveValue)
})
break
}
case 'REJECTED':{
// 将失败回调放入事件队列中
setTimeOut(() => {
fixedOnRejected(this.rejectValue)
})
break
}
case 'PENDING': {
this.onFulfilledList.push(() => {
fixedOnfulfilled(this.resolveValue)
})
this.onRejectedList.push(() => {
fixedOnRejected(this.rejectValue)
})
}
}
resolve和reject在事件循环末尾执行,因此也需要添加异步
resolve(val) {
setTimeOut(() => {
if(this.status !== 'PENDING') return // 确保只能执行一次resolve或者reject
this.status = 'FULFILLED' // 状态修改
this.resolveValue = val // 收集传进来的值
// 执行回调
this.onFulfilledList.forEach((cb) => {
cb()
})
})
}
reject(err) {
setTimeOut(() => {
if(this.status !== 'PENDING') return
this.status = 'REJECTED'
this.rejectValue = err
// 执行回调
this.onFulfilledList.forEach((cb) => {
cb()
})
})
}
6.最终代码
class MyPromise{
const isFunction = variable => typeof variable === 'function'
constructor(handler) {
if (!isFunction(handle)) {
throw new Error('MyPromise must accept a function as a parameter')
}
this.status = 'PENDING'
this.resolveValue = undefined
this.rejectValue = undefined
this.onFulfilledList = []
this.onRejectedList = []
resolve(val) {
setTimeOut(() => {
if(this.status !== 'PENDING') return
this.status = 'FULFILLED'
this.resolveValue = val
this.onFulfilledList.forEach((cb) => {
cb()
})
})
}
reject(err) {
setTimeOut(() => {
if(this.status !== 'PENDING') return
this.status = 'REJECTED'
this.rejectValue = err
this.onFulfilledList.forEach((cb) => {
cb()
})
})
}
try{
handler(this.resolve.bind(this), this.reject.bind(this))
}catch(err){
this.reject(err)
}
}
}
MyPromise.prototype.then(onFulfilled, onRejected) {
return promise2 = new MyPromise((resolve, reject) => {
fixedOnfulfilled(value) {
try {
if(!isFunction(onFulfilled)) {
resolve(value)
}else {
let res = onFulfilled(value)
if(res instanceof MyPromise) {
res.then(resolve, reject)
}else{
resolve(value)
}
}
}catch(err) {
reject(err)
}
}
fixedOnRejected(err) {
try {
if(!isFunction(onRejected)) {
reject(err)
}else {
let res = onRejected(err)
if(res instanceof MyPromise) {
res.then(resolve, reject)
}else{
reject(err)
}
}
}catch(err) {
reject(err)
}
}
switch(this.status){
case 'FULFILLED':{
setTimeOut(() => {
fixedOnfulfilled(this.resolveValue)
})
break
}
case 'REJECTED':{
setTimeOut(() => {
fixedOnRejected(this.rejectValue)
})
break
}
case 'PENDING': {
this.onFulfilledList.push(() => {
fixedOnfulfilled(this.resolveValue)
})
this.onRejectedList.push(() => {
fixedOnRejected(this.rejectValue)
})
}
}
})
}