今天本来想学习一下promise并总结一下,但是发现了 juejin.cn/post/684490… 写的很好,里面不止讲述了promise原理还有 async/await实现,Generator实现 学习了一波,本篇只相当于个人笔记。
Promise/A+规范
- 术语
promise是一个包含了兼容promise规范then方法的对象或函数thenable是一个包含了then方法的对象或函数value是任何javascript值exception是由throw表达式刨出来的值reason是用于描述promise被拒绝的原因的值
- 要求
promise必须是在pending,fulfilled,rejected状态之一,当promise转变成fulfilled,rejected状态时,promise的状态就不能改变了。
promise.then(onFulfilled, onRejected),promise.then要接受2个参数,但是这个2个参数都是可选的,如果onFulfilled, onRejected其中不是函数就忽略。onFulfilled可以理解为一个成功的函数他必须在promise fulfilled后调用,value是第一个参数onRejected可以理解为一个失败的函数他必须在promise rejected后调用,reason是第一个参数then的返回值必须是一个promise
promise小例子
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功函数')
}, 1000)
})
promise1.then((success) => {
console.log('-----------success---------------------', success)
}, (err) => {
console.log('--------------err------------------', err)
})
// -----------success--------------------- 成功函数
promise的then方法会搜集new Promise里面的resolve, reject函数,当executor()在执行异步任务的时候,触发resolve/reject从相应的队列中取出回调依次执行
收集依赖 -> 触发通知 -> 取出依赖执行
then收集依赖 -> 异步触发resolve -> resolve执行依赖
手写一个简答的promise
class MyPromise {
constructor(executor) {
this.resolveGroup = []; // 存放then搜集的resolve函数
this.rejectGroup = []; //存放then搜集的reject函数
let currentResolve = (val) => {
while (this.resolveGroup.length) {
const cb = this.resolveGroup.shift();
cb(val)
}
}
let currentReject = (val) => {
while (this.rejectGroup.length) {
const cb = this.rejectGroup.shift();
cb(val)
}
}
executor(currentResolve, currentReject)
}
// 搜集函数
then(resolveFun, rejectFun) {
this.resolveGroup.push(resolveFun);
this.rejectGroup.push(rejectFun);
}
}
// 测试MyPromise
const promise1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('成功函数')
}, 1000)
})
promise1.then((success) => {
console.log('-----------success---------------------', success)
}, (err) => {
console.log('--------------err------------------', err)
})
promise加入status
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
this.resolveGroup = []; // 存放then搜集的resolve函数
this.rejectGroup = []; //存放then搜集的reject函数
this.status = PENDING; // 在promise 中状态从pending开始,一旦变化,就不能再次更改
let currentResolve = (val) => {
if (this.status !== PENDING) return;
this.status = FULFILLED;
while (this.resolveGroup.length) {
const cb = this.resolveGroup.shift();
cb(val)
}
}
let currentReject = (val) => {
if (this.status !== PENDING) return;
this.status = REJECTED;
while (this.rejectGroup.length) {
const cb = this.rejectGroup.shift();
cb(val)
}
}
executor(currentResolve, currentReject)
}
// 搜集函数
then(resolveFun, rejectFun) {
this.resolveGroup.push(resolveFun);
this.rejectGroup.push(rejectFun);
}
}
const promise1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('成功函数')
}, 1000)
})
promise1.then((success) => {
console.log('-----------success---------------------', success)
}, (err) => {
console.log('--------------err------------------', err)
})
promise.then 的链式调用实现
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
this.resolveGroup = []; // 存放then搜集的resolve函数
this.rejectGroup = []; //存放then搜集的reject函数
this.status = PENDING; // 在promise 中状态从pending开始,一旦变化,就不能再次更改
let currentResolve = (val) => {
if (this.status !== PENDING) return;
this.status = FULFILLED;
while (this.resolveGroup.length) {
const cb = this.resolveGroup.shift();
cb(val)
}
}
let currentReject = (val) => {
if (this.status !== PENDING) return;
this.status = REJECTED;
while (this.rejectGroup.length) {
const cb = this.rejectGroup.shift();
cb(val)
}
}
executor(currentResolve, currentReject)
}
// 搜集函数
then(resolveFun, rejectFun) {
// then 为了实现链式调用,要返回一个新的promise
return new MyPromise((resolve, reject) => {
// 把resolveFun重新包装一下,并且要判断一下resolveFun的返回着,如果返回值
const fulfilledFn = value => {
try {
const x = resolveFun(value);
x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
} catch (e) {
reject(e)
}
}
// 搜集当前 resolveFun 返回的新的函数
this.resolveGroup.push(fulfilledFn);
const rejectedFn = value => {
try {
const x = rejectFun(value);
x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
} catch (e) {
reject(e)
}
}
this.resolveGroup.push(rejectedFn);
})
// this.resolveGroup.push(resolveFun);
// this.rejectGroup.push(rejectFun);
}
}
const promise1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 1000)
})
promise1.then((res) => {
console.log('--------------res2------------------', res)
return 2
}).then((res) => {
console.log('--------------res3------------------', res)
return 3
}).then((res) => {
console.log('-------------res4-------------------', res)
})
值穿透和状态变更
- 值穿透:
then接收2个参数作回调,但是resolve, reject这个2个参数是可选的,并且,当传入的参数不是函数时,要忽略,所以要对参数的类型做判断。 - 状态变更:在
promise中时长会有状态是fulfilled和rejected时,resolve()和reject()在then之前就已经执行。
// 官方例子 Promise.resolve().then() resolve()方法在then之前执行
const promise1 = Promise.resolve(123);
promise1.then(function(value) {
console.log(value);
// expected output: 123
});
实现值穿透和状态变更
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
this.resolveGroup = []; // 存放then搜集的resolve函数
this.rejectGroup = []; //存放then搜集的reject函数
this.status = PENDING; // 在promise 中状态从pending开始,一旦变化,就不能再次更改
this.value = undefined;
let currentResolve = (val) => {
if (this.status !== PENDING) return;
this.status = FULFILLED;
this.value = val;
while (this.resolveGroup.length) {
const cb = this.resolveGroup.shift();
cb(val)
}
}
let currentReject = (val) => {
if (this.status !== PENDING) return;
this.status = REJECTED;
this.value = val;
while (this.rejectGroup.length) {
const cb = this.rejectGroup.shift();
cb(val)
}
}
executor(currentResolve, currentReject)
}
// 搜集函数
then(resolveFun, rejectFun) {
// 值穿透,参数判断
typeof resolveFun === 'function' ? null : resolveFun = value => value
typeof rejectFun === 'function' ? null : rejectFun = error => error
// then 为了实现链式调用,要返回一个新的promise
return new MyPromise((resolve, reject) => {
// 把resolveFun重新包装一下,并且要判断一下resolveFun的返回着,如果返回值
const fulfilledFn = value => {
try {
const x = resolveFun(value);
x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
} catch (e) {
reject(e)
}
}
const rejectedFn = value => {
try {
const x = rejectFun(value);
x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
} catch (e) {
reject(e)
}
}
// 搜集当前 resolveFun 返回的新的函数
// 当前状态不是pending的时候,函数直接执行,不再搜集
if (this.status === PENDING) {
this.resolveGroup.push(fulfilledFn);
this.rejectGroup.push(rejectedFn);
} else if (this.status === FULFILLED) {
fulfilledFn(this.value)
} else {
rejectedFn(this.value)
}
})
// this.resolveGroup.push(resolveFun);
// this.rejectGroup.push(rejectFun);
}
}
const promise1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 1000)
})
promise1.then(2, (err) => {
console.log('------------err--------------------', err)
})
// 没有任何输出
兼容同步任务
Promise的默认实现是放进了微任务队列,我们的实现(包括大多数Promise手动实现和polyfill的转化)都是使用setTimeout放入了宏任务队列(当然我们也可以用MutationObserver模拟微任务)
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
this.resolveGroup = []; // 存放then搜集的resolve函数
this.rejectGroup = []; //存放then搜集的reject函数
this.status = PENDING; // 在promise 中状态从pending开始,一旦变化,就不能再次更改
this.value = undefined;
let currentResolve = (val) => {
const fun = () => {
if (this.status !== PENDING) return;
this.status = FULFILLED;
this.value = val;
while (this.resolveGroup.length) {
const cb = this.resolveGroup.shift();
cb(val)
}
}
// 为了兼容同步任务,特定设置的setTimeout
setTimeout(fun)
}
let currentReject = (val) => {
const fun = () => {
if (this.status !== PENDING) return;
this.status = REJECTED;
this.value = val;
while (this.rejectGroup.length) {
const cb = this.rejectGroup.shift();
cb(val)
}
}
setTimeout(fun)
}
executor(currentResolve, currentReject)
}
// 搜集函数
then(resolveFun, rejectFun) {
// 值穿透,参数判断
typeof resolveFun === 'function' ? null : resolveFun = value => value
typeof rejectFun === 'function' ? null : rejectFun = error => error
// then 为了实现链式调用,要返回一个新的promise
return new MyPromise((resolve, reject) => {
// 把resolveFun重新包装一下,并且要判断一下resolveFun的返回着,如果返回值
const fulfilledFn = value => {
try {
const x = resolveFun(value);
x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
} catch (e) {
reject(e)
}
}
const rejectedFn = value => {
try {
const x = rejectFun(value);
x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
} catch (e) {
reject(e)
}
}
// 搜集当前 resolveFun 返回的新的函数
// 当前状态不是pending的时候,函数直接执行,不再搜集
if (this.status === PENDING) {
this.resolveGroup.push(fulfilledFn);
this.rejectGroup.push(rejectedFn);
} else if (this.status === FULFILLED) {
fulfilledFn(this.value)
} else {
rejectedFn(this.value)
}
})
// this.resolveGroup.push(resolveFun);
// this.rejectGroup.push(rejectFun);
}
}
更好理解Promise / async / Generator 实现&原理请移步