1.实现promise的基本结构,可以先来看一下promise的使用
const test = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 2000)
})
test.then(res => {
console.log(res)
})
可以看出,我们在new一个promise实例的时候传入了一个执行器(resolve, reject) => { }
,执行函数里有两个参数,resolve、reject 方法都是在 Promise 类里定义的,外部调用这个方法时,还可以往里面传入参数,Promise 拿到这个值后保存起来,以供 .then 调用, .then() 方法需要指定成功的回调和失败的回调,根据 status 状态的不同来执行对应的回调.接下来我们就可以实现这个基本结构
class Promise {
// 参数executor为一个执行器
constructor(executor) {
this.status = 'pending' //1.等待状态为pending 2.成功状态为fulfilled 3.失败状态为rejected
this.value = ''
this.reason = ''
const resolve = function (value) {
this.value = value
if (this.status === 'pending') {
this.status = 'fulfilled'
}
}
const reject = function (reason) {
this.reason = reason
if (this.status === 'pending') {
this.status = rejected
}
}
executor(resolve, reject)
}
then (onfulfilled, onrejected) {
if (this.status === 'fulfilled') {
onfulfilled(this.value) // 将之前的resolve的值传入
} else if (this.status === 'rejected') {
onrejected(this.reason) // 将之前rejected的值传入
}
}
}
以上代码实现了:
1、promise状态的切换
2、then方法根据响应的状态执行对应的回调函数
2.但是以上的promise不支持异步,这里我们需要在Promise类中存放两个数组,分别保存成功回调和失败的回调,因为可以then多次,所以需要将这些函数放在数组中,代码继续补充
class Promise {
// 参数executor为一个执行器
constructor(executor) {
this.status = 'pending' //1.等待状态为pending 2.成功状态为fulfilled 3.失败状态为rejected
this.value = ''
this.reason = ''
this.onfulfilledCallbacks = [] // 储存成功回调的数组
this.onrejectedCallbacks = [] // 储存失败回调的数组
const resolve = function (value) {
this.value = value
if (this.status === 'pending') {
this.status = 'fulfilled'
if(this.onfulfilledCallbacks && this.onfulfilledCallbacks.length > 0){
this.onfulfilledCallbacks.forEach(fn => fn(value))
}
}
}
const reject = function (reason) {
this.reason = reason
if (this.status === 'pending') {
this.status = rejected
if(this.onrejectedCallbacks && this.onrejectedCallbacks.length > 0){
this.onrejectedCallbacks.forEach(fn => fn(reason))
}
}
}
executor(resolve, reject)
}
then (onfulfilled, onrejected) {
if (this.status === 'fulfilled') {
onfulfilled(this.value) // 将之前的resolve的值传入
} else if (this.status === 'rejected') {
onrejected(this.reason) // 将之前rejected的值传入
} else if (this.status === 'pengind'){ //当异步执行status的状态还没有改变的时候,将回调函数先进行储存
this.onfulfilledCallbacks.push(onfulfilled)
this.onrejectedCallbacks.push(onrejected)
}
}
}
以上代码实现了:
1、promise状态的切换
2、then方法根据响应的状态执行对应的回调函数
3、支持promise异步
***3.***接下来要实现的就是then()方法的链式调用。
这里需要注意的是then()方法返回的是一个全新的promise实例,这样才可以保证后续的then()方法中status状态是可以改变的,继续修改代码
class Promise {
constructor(executor) {
this.status = 'pending'
this.value = ''
this.reason = ''
this.onfulfilledCallbacks = []
this.onrejectedCallbacks = []
const resolve = function (value) {
this.value = value
if (this.status === 'pending') {
this.status = 'fulfilled'
if (this.onfulfilledCallbacks && this.onfulfilledCallbacks.length > 0) {
this.onfulfilledCallbacks.forEach(fn => fn(value))
}
}
}
const reject = function (reason) {
this.reason = reason
if (this.status === 'pending') {
this.status = rejected
if (this.onrejectedCallbacks && this.onrejectedCallbacks.length > 0) {
this.onrejectedCallbacks.forEach(fn => fn(reason))
}
}
}
executor(resolve, reject)
}
then (onfulfilled, onrejected) {
const promise2 = new Promise((resolve, reject) => {
if (this.status === 'fulfilled') {
const x = onfulfilled(this.value)
resolve(x)
} else if (this.status === 'rejected') {
const r = onrejected(this.reason)
resolve(r)
} else if (this.status === 'pengind') {
this.onfulfilledCallbacks.push((value) => {
const x = onfulfilled(value)
resolve(x)
})
this.onrejectedCallbacks.push((reason => {
const r = onrejected(r)
resolve(r) // 注意失败的回调的时候状态status依然是fulfilled
}))
}
})
return promise2
}
}
以上代码实现了:
1、promise状态的切换
2、then方法根据响应的状态执行对应的回调函数
3、支持promise异步
4、支持then()方法的链式回调,返回一个promise实例
4.接下来我们考虑的问题是,上面then()中将回调函数的返回值直接resolve出去了,如果是一个普通值是没有问题的,但是如果是一个promise对象就不可以这么做了。如果返回值是一个promise的实例,我们就必须继续调用then()方法,让这个 promise 执行,拿到这个 promise resolve 的值,继续修改代码(这里列出then方法的修改和添加的resolvePromise方法)
then (onfulfilled, onrejected) {
const promise2 = new Promise((resolve, reject) => {
// 这里加定时器,为了让里面的代码异步,保证传入 promise2 的时候, promise2 已经初始化完了,
// 这也就解释了为什么 Promise 的 then 方法是异步的
setTimeout(() => {
if (this.status === 'fulfilled') {
const x = onfulfilled(this.value)
resolvePromise(x)
} else if (this.status === 'rejected') {
const r = onrejected(this.reason)
resolvePromise(r)
} else if (this.status === 'pengind') {
this.onfulfilledCallbacks.push((value) => {
const x = onfulfilled(value)
resolvePromise(x)
})
this.onrejectedCallbacks.push((reason => {
const r = onrejected(r)
resolvePromise(r) // 注意失败的回调的时候状态status依然是fulfilled
}))
}
}, 0)
})
return promise2
}
function resolvePromise (promise2, x, resolve, reject) {
if (promise2 === x) {
return new TypeError('循环引用!')
} else if (x instanceof Promise) {
x.then(y => {
resolvePromise(promise2, y, resolve, reject)
}, r => {
reject(r)
})
} else {
resolve(x)
}
}
以上代码实现了:
1、promise状态的切换
2、then方法根据响应的状态执行对应的回调函数
3、支持promise异步
4、支持then()方法的链式回调,返回一个promise实例,并对then方法可能返回promise实例进行处理
5.接下来考虑的问题是,假如我们在new Promise
的时候resolve
值也是一个promise
,也需要等这个promise
执行完then
,所以对对代码做如下修改
const resolve = function (value) {
if(value instanceof Promise){
return value.then(resolve, reject)
}
this.value = value
if (this.status === 'pending') {
this.status = 'fulfilled'
if (this.onfulfilledCallbacks && this.onfulfilledCallbacks.length > 0) {
this.onfulfilledCallbacks.forEach(fn => fn(value))
}
}
}
以上代码实现了:
1、promise
状态的切换
2、then
方法根据响应的状态执行对应的回调函数
3、支持promise
异步
4、支持then()
方法的链式回调,返回一个promise
实例,并对then
方法可能返回promise实例进行处理
5、对第一次new Promise
时resolve
值可能是promise
的实例做处理
6.接下来对错误捕获进行处理,其实就是加上try---catch
语句
class Promise {
constructor(executor) {
this.status = 'pending'
this.value = ''
this.reason = ''
this.onfulfilledCallbacks = []
this.onrejectedCallbacks = []
const resolve = function (value) {
if (value instanceof Promise) {
return value.then(resolve, reject)
}
this.value = value
if (this.status === 'pending') {
this.status = 'fulfilled'
if (this.onfulfilledCallbacks && this.onfulfilledCallbacks.length > 0) {
this.onfulfilledCallbacks.forEach(fn => fn(value))
}
}
}
const reject = function (reason) {
this.reason = reason
if (this.status === 'pending') {
this.status = rejected
if (this.onrejectedCallbacks && this.onrejectedCallbacks.length > 0) {
this.onrejectedCallbacks.forEach(fn => fn(reason))
}
}
}
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
then (onfulfilled, onrejected) {
const promise2 = new Promise((resolve, reject) => {
// 这里加定时器,为了让里面的代码异步,保证传入 promise2 的时候, promise2 已经初始化完了,
// 这也就解释了为什么 Promise 的 then 方法是异步的
setTimeout(() => {
if (this.status === 'fulfilled') {
try {
const x = onfulfilled(this.value)
resolvePromise(x)
} catch (err) {
reject(err)
}
} else if (this.status === 'rejected') {
try {
const r = onrejected(this.reason)
resolvePromise(r)
} catch (err) {
reject(err)
}
} else if (this.status === 'pengind') {
this.onfulfilledCallbacks.push((value) => {
try {
const x = onfulfilled(value)
resolvePromise(x)
} catch (err) {
reject(err)
}
})
this.onrejectedCallbacks.push((reason => {
try {
const r = onrejected(r)
resolvePromise(r) // 注意失败的回调的时候状态status依然是fulfilled
} catch (err) {
reject(err)
}
}))
}
}, 0)
})
return promise2
}
}
function resolvePromise (promise2, x, resolve, reject) {
if (promise2 === x) {
return new TypeError('循环引用!')
} else if (x instanceof Promise) {
x.then(y => {
resolvePromise(promise2, y, resolve, reject)
}, r => {
reject(r)
})
} else {
resolve(x)
}
}
7.promise
已经基本实现了,但是我们还需要考虑一些极端情况,比如连续的then()
方法返回空值,这样就需要给then()
方法默认的函数,不传值的话直接返回,一行代码就可以搞定
then (onfulfilled = v => v, onrejected = r => r)
8.把静态的方法可以顺便实现一下,这里就不做过多说明
Promise.resolve = function (value) {
return new Promise((resolve, reject) => {
resolve(value)
})
}
Promise.reject = function (reason) {
return new Promise((resolve, reject) => {
reject(reason)
})
}
9.最后还有两个重点应该看一下,就是promise.all
和promise.race
的实现
Promise.all 接收一个任务数组,数组元素 (可能是 promise 或其他值) 并发执行,如果是 Promise 就执行他,拿到 resolve 的值,如果是其他普通值就直接存起来,执行完成后的值存放在一个结果数组中
Promise.all 执行后会返回一个 新的 Promise 实例,并且会将结果数组 resolve 出去,下一个 then 中可以拿到
很明显,我们只需要在内部实现一个计数器,每个任务元素完成后将计数器加 1,只要达到了任务数组的 length 长度即可
Promise.race这个方法就是:比比谁最快执行完
遍历数组参数,执行每一个元素 (同样的,注意区分 Promise 和 非Promise)
对于 Promise 实例,Promise 执行完成后,直接 resolve
对于普通值,直接 resolve
Promise.all = function (p) {
let result = []
let count = 0
function processData (index, value) {
result[index] = value
if (++count === p.length) {
resolve(result)
}
}
p.forEach((cur, index) => {
if (cur instanceof Promise) {
cur.then(v => {
processData(index, v)
}, r => {
this.reject(r)
})
} else {
processData(cur)
}
})
}
Promise.race = function(p) {
return new Promise((resolve, reject) => {
p.forEach(cur => {
if(cur instanceof Promise){
cur.then(v => {
resolve(v)
})
}else{
resolve(cur)
}
})
})
}
最后再来复习一下Promise的实现过程
1、promise
状态的切换
2、then
方法根据响应的状态执行对应的回调函数
3、支持promise
异步
4、支持then()
方法的链式回调,返回一个promise
实例,并对then
方法可能返回promise实例进行处理
5、对第一次new Promise
时resolve
值可能是promise
的实例做处理
6、捕获并抛出错误
7、then方法设置默认值
8、promise静态方法的实现
最后的最后附上全部的代码
class Promise {
constructor(executor) {
this.status = 'pending' //等待状态为pending,成功为fulfilled,失败为rejected
this.value = ''
this.reason = ''
this.onfulfilledCallbacks = [] //存储then中成功的回调
this.onrejectedCallbacks = [] //存储then中失败的回调
const resolve = (value) => {
if (value instanceof Promise) {
value.then(resolve, reject)
}
if (this.status === 'pending') {
this.value = value
this.status = 'fulfilled'
if (this.onfulfilledCallbacks && this.onfulfilledCallbacks.length > 0) {
this.onfulfilledCallbacks.forEach(fn => fn(value))
}
}
}
const reject = (reason) => {
this.reason = reason
if (this.status === 'pending') {
this.status = 'rejected'
if (this.onrejectedCallbacks && this.onrejectedCallbacks.length > 0) {
this.onrejectedCallbacks.forEach(fn => fn(this.reason))
}
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then (onfulfilled = v => v, onrejected = r => r) {
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
if (this.status === 'fulfilled') {
try {
const x = onfulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
} else if (this.status === 'rejected') {
try {
const r = onrejected(this.reason)
resolvePromise(promise2, r, resolve, reject)
} catch (e) {
reject(e)
}
} else if (this.status === 'pending') {
this.onfulfilledCallbacks.push(value => {
try {
const x = onfulfilled(value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
this.onrejectedCallbacks.push(reason => {
try {
const r = onrejected(reason)
resolvePromise(promise2, r, resolve, reject)
} catch (e) {
reject(e)
}
})
}
}, 0)
})
return promise2
}
catch (rejectFn) {
return this.then(null, rejectFn) // catch方法其实就是第一个参数为null的then方法
}
}
function resolvePromise (promise2, x, resolve, reject) {
if (x === promise2) {
return new TypeError('循环引用')
} else if (x instanceof Promise) { // x是promise的实例
x.then(y => {
this.resolvePromise(promise2, y, resolve, reject)
}, r => {
reject(r)
})
} else { // 普通值,直接resolve
resolve(x)
}
}
Promise.resolve = function (value) {
return new Promise((resolve, reject) => {
resolve(value)
})
}
Promise.reject = function (reason) {
return new Promise((resolve, reject) => {
reject(reason)
})
}
Promise.all = function (p) {
let result = []
let count = 0
function processData (index, value) {
result[index] = value
if (++count === p.length) {
resolve(result)
}
}
p.forEach((cur, index) => {
if (cur instanceof Promise) {
cur.then(v => {
processData(index, cur)
}, r => {
reject(r)
})
} else {
processData(index, cur)
}
})
}
Promise.race = function (p) {
return new Promise((resolve, reject) => {
p.forEach(cur => {
if (cur instanceof Promise) {
// 指向promise,然后再resolve
cur.then(r => {
resolve(r)
})
} else { // 不是promise的话直接resolvez
resolve(cur)
}
})
})
}
分享就到这里结束了,希望对大家有帮助!