手写Promise
手写Promise结构的设计
const PROMISE_PENDING = 'pending'
const PROMISE_FULFILLED = 'fulfilled'
const PROMISE_REJECTED = 'rejected'
class FhPromise {
constructor(executor) {
this.status = PROMISE_PENDING
this.value = undefined
this.reason = undefined
const resolve = (value) => {
if(this.status === PROMISE_PENDING) {
queueMicrotask(() => {
console.log('resolve的queue');
this.status = PROMISE_FULFILLED
this.value = value
this.onfulfilled(this.value)
});
}
}
const reject = (reason) => {
if(this.status === PROMISE_PENDING) {
queueMicrotask(() => {
console.log('reject的queue');
this.status = PROMISE_REJECTED
this.reason = reason
this.onrejected(this.reason)
})
}
}
executor(resolve, reject)
}
then(onfulfilled, onrejected) {
console.log('then方法');
this.onfulfilled = onfulfilled
this.onrejected = onrejected
}
}
const promise = new FhPromise((resolve, reject) => {
resolve(111)
})
promise.then(res => {
console.log('res1:', res);
},err => {
console.log('err1', err);
})
promise.then(res => {
console.log('res2:', res);
},err => {
console.log('err2', err);
})
手写Promise~then优化一
const PROMISE_PENDING = 'pending'
const PROMISE_FULFILLED = 'fulfilled'
const PROMISE_REJECTED = 'rejected'
class FhPromise {
constructor(executor) {
this.status = PROMISE_PENDING
this.value = undefined
this.reason = undefined
this.onfulfilledFns = []
this.onrejectedFns = []
const resolve = (value) => {
if(this.status === PROMISE_PENDING) {
queueMicrotask(() => {
if(this.status !== PROMISE_PENDING) return
console.log('resolve的queue');
this.status = PROMISE_FULFILLED
this.value = value
this.onfulfilledFns.forEach(fn => {
fn(this.value)
})
});
}
}
const reject = (reason) => {
if(this.status === PROMISE_PENDING) {
queueMicrotask(() => {
if(this.status !== PROMISE_PENDING) return
console.log('reject的queue');
this.status = PROMISE_REJECTED
this.reason = reason
this.onrejectedFns.forEach(fn => {
fn(this.reason)
})
})
}
}
executor(resolve, reject)
}
then(onfulfilled, onrejected) {
console.log('then方法');
if(this.status === PROMISE_FULFILLED && onfulfilled) {
onfulfilled(this.value)
}
if(this.status === PROMISE_REJECTED && onrejected) {
onrejected(this.reason)
}
if(this.status === PROMISE_PENDING) {
console.log('-----------------');
this.onfulfilledFns.push(onfulfilled)
this.onrejectedFns.push(onrejected)
}
}
}
const promise = new FhPromise((resolve, reject) => {
resolve(111)
})
promise.then(res => {
console.log('res1:', res);
},err => {
console.log('err1:', err);
})
promise.then(res => {
console.log('res2:', res);
},err => {
console.log('err2:', err);
})
setTimeout(() => {
promise.then(res => {
console.log('res3:', res);
}, err => {
console.log('err3:', err);
})
}, 1000);
手写Promise~then优化二
const PROMISE_PENDING = 'pending'
const PROMISE_FULFILLED = 'fulfilled'
const PROMISE_REJECTED = 'rejected'
function execFnWithCatchError(execFn, value, resolve, reject) {
try {
const result = execFn(value)
if(result === 'undefined') return
console.log('xxxxxx', result);
resolve(result)
} catch (error) {
reject(error)
}
}
class FhPromise {
constructor(executor) {
this.status = PROMISE_PENDING
this.value = undefined
this.reason = undefined
this.onfulfilledFns = []
this.onrejectedFns = []
const resolve = (value) => {
if(this.status === PROMISE_PENDING) {
queueMicrotask(() => {
if(this.status !== PROMISE_PENDING) return
console.log('resolve的queue');
this.status = PROMISE_FULFILLED
this.value = value
this.onfulfilledFns.forEach(fn => {
fn()
console.log('```````````````````````');
})
});
}
}
const reject = (reason) => {
if(this.status === PROMISE_PENDING) {
queueMicrotask(() => {
if(this.status !== PROMISE_PENDING) return
this.status = PROMISE_REJECTED
this.reason = reason
this.onrejectedFns.forEach(fn => {
fn()
})
})
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onfulfilled, onrejected) {
console.log('then方法');
return new FhPromise((resolve, reject) => {
if(this.status === PROMISE_FULFILLED && onfulfilled) {
execFnWithCatchError(onfulfilled, this.value, resolve, reject)
}
if(this.status === PROMISE_REJECTED && onrejected) {
execFnWithCatchError(onrejected, this.reason, resolve, reject)
}
if(this.status === PROMISE_PENDING) {
console.log('----------------');
this.onfulfilledFns.push(() => {
execFnWithCatchError(onfulfilled, this.value, resolve, reject)
})
this.onrejectedFns.push(() => {
execFnWithCatchError(onrejected, this.reason, resolve, reject)
})
}
})
}
}
const promise = new FhPromise((resolve, reject) => {
resolve(111)
})
promise.then(res => {
console.log('res1:', res);
return 'aaa'
},err => {
console.log('err1:', err);
return 'bbb'
}).then(res => {
console.log('res2:', res);
}, err => {
console.log('err2:', err);
})
手写Promise~catch方法设计
const PROMISE_PENDING = 'pending'
const PROMISE_FULFILLED = 'fulfilled'
const PROMISE_REJECTED = 'rejected'
function execFnWithCatchError(execFn, value, resolve, reject) {
try {
const result = execFn(value)
if(result === 'undefined') return
resolve(result)
} catch (error) {
reject(error)
}
}
class FhPromise {
constructor(executor) {
this.status = PROMISE_PENDING
this.value = undefined
this.reason = undefined
this.onfulfilledFns = []
this.onrejectedFns = []
const resolve = (value) => {
if(this.status === PROMISE_PENDING) {
queueMicrotask(() => {
if(this.status !== PROMISE_PENDING) return
this.status = PROMISE_FULFILLED
this.value = value
this.onfulfilledFns.forEach(fn => {
fn()
})
});
}
}
const reject = (reason) => {
if(this.status === PROMISE_PENDING) {
queueMicrotask(() => {
if(this.status !== PROMISE_PENDING) return
this.status = PROMISE_REJECTED
this.reason = reason
this.onrejectedFns.forEach(fn => {
fn()
})
})
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onfulfilled, onrejected) {
function defaultOnRejected(err) { throw err }
onrejected = onrejected || defaultOnRejected
return new FhPromise((resolve, reject) => {
if(this.status === PROMISE_FULFILLED && onfulfilled) {
execFnWithCatchError(onfulfilled, this.value, resolve, reject)
}
if(this.status === PROMISE_REJECTED && onrejected) {
execFnWithCatchError(onrejected, this.reason, resolve, reject)
}
if(this.status === PROMISE_PENDING) {
if(onfulfilled) this.onfulfilledFns.push(() => {
execFnWithCatchError(onfulfilled, this.value, resolve, reject)
})
if(onrejected) {
this.onrejectedFns.push(() => {
execFnWithCatchError(onrejected, this.reason, resolve, reject)
})
}
}
})
}
catch(onrejected) {
this.then(undefined, onrejected)
}
}
const promise = new FhPromise((resolve, reject) => {
reject(222)
})
promise.then(res => {
console.log('res1:', res);
}).catch(err => {
console.log('err2', err);
})
手写Promise~finally方法设计
const PROMISE_PENDING = 'pending'
const PROMISE_FULFILLED = 'fulfilled'
const PROMISE_REJECTED = 'rejected'
function execFnWithCatchError(execFn, value, resolve, reject) {
try {
const result = execFn(value)
if(result === 'undefined') return
resolve(result)
} catch (error) {
reject(error)
}
}
class FhPromise {
constructor(executor) {
this.status = PROMISE_PENDING
this.value = undefined
this.reason = undefined
this.onfulfilledFns = []
this.onrejectedFns = []
const resolve = (value) => {
if(this.status === PROMISE_PENDING) {
queueMicrotask(() => {
if(this.status !== PROMISE_PENDING) return
this.status = PROMISE_FULFILLED
this.value = value
this.onfulfilledFns.forEach(fn => {
fn()
})
});
}
}
const reject = (reason) => {
if(this.status === PROMISE_PENDING) {
queueMicrotask(() => {
if(this.status !== PROMISE_PENDING) return
this.status = PROMISE_REJECTED
this.reason = reason
this.onrejectedFns.forEach(fn => {
fn()
})
})
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onfulfilled, onrejected) {
function defaultOnRejected(err) { throw err }
onrejected = onrejected || defaultOnRejected
function defaultOnFulfilled(value) { return value }
onfulfilled = onfulfilled || defaultOnFulfilled
return new FhPromise((resolve, reject) => {
if(this.status === PROMISE_FULFILLED && onfulfilled) {
execFnWithCatchError(onfulfilled, this.value, resolve, reject)
}
if(this.status === PROMISE_REJECTED && onrejected) {
execFnWithCatchError(onrejected, this.reason, resolve, reject)
}
if(this.status === PROMISE_PENDING) {
if(onfulfilled) this.onfulfilledFns.push(() => {
execFnWithCatchError(onfulfilled, this.value, resolve, reject)
})
if(onrejected) this.onrejectedFns.push(() => {
execFnWithCatchError(onrejected, this.reason, resolve, reject)
})
}
})
}
catch(onrejected) {
return this.then(undefined, onrejected)
}
finally(onFinally) {
this.then(() => {
onFinally()
}, () => {
onFinally()
})
}
}
const promise = new FhPromise((resolve, reject) => {
resolve(111)
})
promise.then(res => {
console.log('res1:', res);
return 'aaa'
}).catch(err => {
console.log('err2', err);
}).finally(() => {
console.log('finally');
})
手写Promiseresolvereject(类方法)
const PROMISE_PENDING = 'pending'
const PROMISE_FULFILLED = 'fulfilled'
const PROMISE_REJECTED = 'rejected'
function execFnWithCatchError(execFn, value, resolve, reject) {
try {
const result = execFn(value)
if(result === 'undefined') return
resolve(result)
} catch (error) {
reject(error)
}
}
class FhPromise {
constructor(executor) {
this.status = PROMISE_PENDING
this.value = undefined
this.reason = undefined
this.onfulfilledFns = []
this.onrejectedFns = []
const resolve = (value) => {
if(this.status === PROMISE_PENDING) {
queueMicrotask(() => {
if(this.status !== PROMISE_PENDING) return
this.status = PROMISE_FULFILLED
this.value = value
this.onfulfilledFns.forEach(fn => {
fn()
})
});
}
}
const reject = (reason) => {
if(this.status === PROMISE_PENDING) {
queueMicrotask(() => {
if(this.status !== PROMISE_PENDING) return
this.status = PROMISE_REJECTED
this.reason = reason
this.onrejectedFns.forEach(fn => {
fn()
})
})
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onfulfilled, onrejected) {
function defaultOnRejected(err) { throw err }
onrejected = onrejected || defaultOnRejected
function defaultOnFulfilled(value) { return value }
onfulfilled = onfulfilled || defaultOnFulfilled
return new FhPromise((resolve, reject) => {
if(this.status === PROMISE_FULFILLED && onfulfilled) {
execFnWithCatchError(onfulfilled, this.value, resolve, reject)
}
if(this.status === PROMISE_REJECTED && onrejected) {
execFnWithCatchError(onrejected, this.reason, resolve, reject)
}
if(this.status === PROMISE_PENDING) {
if(onfulfilled) this.onfulfilledFns.push(() => {
execFnWithCatchError(onfulfilled, this.value, resolve, reject)
})
if(onrejected) this.onrejectedFns.push(() => {
execFnWithCatchError(onrejected, this.reason, resolve, reject)
})
}
})
}
catch(onrejected) {
return this.then(undefined, onrejected)
}
finally(onFinally) {
this.then(() => {
onFinally()
}, () => {
onFinally()
})
}
static resolve(value) {
return new FhPromise(resolve => {
resolve(value)
})
}
static reject(reason) {
return new FhPromise((resolve, reject) => {
reject(reason)
})
}
}
FhPromise.resolve('123').then(res => {
console.log('res1:', res);
})
FhPromise.reject('err mess').catch(err => {
console.log(err);
})
手写PromiseallallSettled
const PROMISE_PENDING = 'pending'
const PROMISE_FULFILLED = 'fulfilled'
const PROMISE_REJECTED = 'rejected'
function execFnWithCatchError(execFn, value, resolve, reject) {
try {
const result = execFn(value)
if(result === 'undefined') return
resolve(result)
} catch (error) {
reject(error)
}
}
class FhPromise {
constructor(executor) {
this.status = PROMISE_PENDING
this.value = undefined
this.reason = undefined
this.onfulfilledFns = []
this.onrejectedFns = []
const resolve = (value) => {
if(this.status === PROMISE_PENDING) {
queueMicrotask(() => {
if(this.status !== PROMISE_PENDING) return
this.status = PROMISE_FULFILLED
this.value = value
this.onfulfilledFns.forEach(fn => {
fn()
})
});
}
}
const reject = (reason) => {
if(this.status === PROMISE_PENDING) {
queueMicrotask(() => {
if(this.status !== PROMISE_PENDING) return
this.status = PROMISE_REJECTED
this.reason = reason
this.onrejectedFns.forEach(fn => {
fn()
})
})
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onfulfilled, onrejected) {
function defaultOnRejected(err) { throw err }
onrejected = onrejected || defaultOnRejected
function defaultOnFulfilled(value) { return value }
onfulfilled = onfulfilled || defaultOnFulfilled
return new FhPromise((resolve, reject) => {
if(this.status === PROMISE_FULFILLED && onfulfilled) {
execFnWithCatchError(onfulfilled, this.value, resolve, reject)
}
if(this.status === PROMISE_REJECTED && onrejected) {
execFnWithCatchError(onrejected, this.reason, resolve, reject)
}
if(this.status === PROMISE_PENDING) {
if(onfulfilled) this.onfulfilledFns.push(() => {
execFnWithCatchError(onfulfilled, this.value, resolve, reject)
})
if(onrejected) this.onrejectedFns.push(() => {
execFnWithCatchError(onrejected, this.reason, resolve, reject)
})
}
})
}
catch(onrejected) {
return this.then(undefined, onrejected)
}
finally(onFinally) {
this.then(() => {
onFinally()
}, () => {
onFinally()
})
}
static resolve(value) {
return new FhPromise(resolve => {
resolve(value)
})
}
static reject(reason) {
return new FhPromise((resolve, reject) => {
reject(reason)
})
}
static all(promises) {
return new FhPromise((resolve, reject) => {
let values = []
promises.forEach((promise) => {
promise.then(res => {
values.push(res)
if(values.length === promises.length){
resolve(values)
}
}, err => {
reject(err)
})
})
})
}
static allSettled(promises) {
return new FhPromise((resolve) => {
let results = []
promises.forEach(promise => {
promise.then(res => {
results.push({ status: PROMISE_FULFILLED, value: res })
if(results.length === promises.length){
resolve(results)
}
}, err => {
results.push({ status: PROMISE_REJECTED, value: err })
if(results.length === promises.length){
resolve(results)
}
})
})
})
}
}
const p1 = new Promise((resolve, reject) => {
setTimeout(() => { resolve(11111) }, 1000);
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => { resolve(22222) }, 2000);
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => { resolve(33333) }, 3000);
})
FhPromise.allSettled([p1, p2, p3]).then( res =>{
console.log(res);
})
手写Promiseraceany
const PROMISE_PENDING = 'pending'
const PROMISE_FULFILLED = 'fulfilled'
const PROMISE_REJECTED = 'rejected'
function execFnWithCatchError(execFn, value, resolve, reject) {
try {
const result = execFn(value)
if(result === 'undefined') return
resolve(result)
} catch (error) {
reject(error)
}
}
class FhPromise {
constructor(executor) {
this.status = PROMISE_PENDING
this.value = undefined
this.reason = undefined
this.onfulfilledFns = []
this.onrejectedFns = []
const resolve = (value) => {
if(this.status === PROMISE_PENDING) {
queueMicrotask(() => {
if(this.status !== PROMISE_PENDING) return
this.status = PROMISE_FULFILLED
this.value = value
this.onfulfilledFns.forEach(fn => {
fn()
})
});
}
}
const reject = (reason) => {
if(this.status === PROMISE_PENDING) {
queueMicrotask(() => {
if(this.status !== PROMISE_PENDING) return
this.status = PROMISE_REJECTED
this.reason = reason
this.onrejectedFns.forEach(fn => {
fn()
})
})
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onfulfilled, onrejected) {
function defaultOnRejected(err) { throw err }
onrejected = onrejected || defaultOnRejected
function defaultOnFulfilled(value) { return value }
onfulfilled = onfulfilled || defaultOnFulfilled
return new FhPromise((resolve, reject) => {
if(this.status === PROMISE_FULFILLED && onfulfilled) {
execFnWithCatchError(onfulfilled, this.value, resolve, reject)
}
if(this.status === PROMISE_REJECTED && onrejected) {
execFnWithCatchError(onrejected, this.reason, resolve, reject)
}
if(this.status === PROMISE_PENDING) {
if(onfulfilled) this.onfulfilledFns.push(() => {
execFnWithCatchError(onfulfilled, this.value, resolve, reject)
})
if(onrejected) this.onrejectedFns.push(() => {
execFnWithCatchError(onrejected, this.reason, resolve, reject)
})
}
})
}
catch(onrejected) {
return this.then(undefined, onrejected)
}
finally(onFinally) {
this.then(() => {
onFinally()
}, () => {
onFinally()
})
}
static resolve(value) {
return new FhPromise(resolve => {
resolve(value)
})
}
static reject(reason) {
return new FhPromise((resolve, reject) => {
reject(reason)
})
}
static all(promises) {
return new FhPromise((resolve, reject) => {
let values = []
promises.forEach((promise) => {
promise.then(res => {
values.push(res)
if(values.length === promises.length){
resolve(values)
}
}, err => {
reject(err)
})
})
})
}
static allSettled(promises) {
return new FhPromise((resolve) => {
let results = []
promises.forEach(promise => {
promise.then(res => {
results.push({ status: PROMISE_FULFILLED, value: res })
if(results.length === promises.length){
resolve(results)
}
}, err => {
results.push({ status: PROMISE_REJECTED, value: err })
if(results.length === promises.length){
resolve(results)
}
})
})
})
}
static race(promises) {
return new FhPromise((resolve, reject) => {
promises.forEach(promise => {
promise.then(res => {
resolve(res)
}, err => {
reject(err)
})
})
})
}
static any(promises) {
return new FhPromise((resolve, reject) => {
let errs = []
promises.forEach(promise => {
promise.then(res => {
resolve(res)
}, err => {
errs.push(err)
if(errs.length === promises.length){
reject(errs)
}
})
})
})
}
}
const p1 = new Promise((resolve, reject) => {
setTimeout(() => { reject('error1') }, 1000);
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => { reject('error2') }, 2000);
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => { reject('error3') }, 3000);
})
FhPromise.any([p1, p2, p3]).then(res => {
console.log('res:', res);
}).catch(err => {
console.log('err:', err);
})