手写promise
promise 共有三个状态 定义状态
const promise_state_pending = 'pending'
const promise_state_fulfilled = 'fulfilled'
const promise_state_onRejected = 'onRejected'
promise 是通过new 来生成的对象 它的参数是一个函数对象并且函数中也有两个参数
class ShkPromise {
constructor ( execFn ) {
const resolve = ( value ) => {
console. log ( value)
}
const rejected = ( err ) => {
}
execFn ( resolve, rejected)
}
}
new ShkPromise ( ( res, rej ) => {
res ( 123 )
}
在确定以res执行后则会执行返回后的对象的then方法
const promise_state_pending = 'pending'
const promise_state_fulfilled = 'fulfilled'
const promise_state_onRejected = 'onRejected'
class ShkPromise {
constructor ( execFn ) {
this . state = promise_state_pending;
this . value = null ;
this . reason = null ;
const resolve = ( value ) => {
this . value = value;
}
const rejected = ( err ) => {
this . reason = err;
}
execFn ( resolve, rejected)
}
then ( execThen ) {
execThen ( this . value)
}
carth ( execCarth ) {
execCarth ( this . reason)
}
}
const promise= new ShkPromise ( ( res, rej ) => {
res ( 123 )
} )
promise. then ( res => {
console. log ( res)
} )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
但是此时会有问题 当把then换成 catch 发现它也可以运行catch里面的函数 故需要将状态改掉
const promise_state_pending = 'pending'
const promise_state_fulfilled = 'fulfilled'
const promise_state_onRejected = 'onRejected'
class ShkPromise {
constructor ( execFn ) {
this . state = promise_state_pending;
this . value = null ;
this . reason = null ;
const resolve = ( value ) => {
this . value = value;
this . state = promise_state_fulfilled;
}
const rejected = ( err ) => {
this . reason = err;
this . state = promise_state_onRejected;
}
execFn ( resolve, rejected)
}
then ( execThen ) {
if ( this . state === promise_state_fulfilled)
execThen ( this . value)
}
catch ( execCatch) {
if ( this . state === promise_state_onRejected)
execCatch ( this . reason)
}
}
const promise = new ShkPromise ( ( res, rej ) => {
rej ( 123 )
} )
promise. catch ( res => {
console. log ( res)
} )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
promise中then调用其实是在微任务中进行的 此时的then是同步
在resolve函数中创建微任务函数queueMicrotask 将 then方法存入一个数组中 等待 微任务执行时再一起执行
const promise_state_pending = 'pending'
const promise_state_fulfilled = 'fulfilled'
const promise_state_onRejected = 'onRejected'
class ShkPromise {
constructor ( execFn ) {
this . state = promise_state_pending;
this . value = null ;
this . reason = null ;
this . successCallbackFn = [ ] ;
this . catchCallbackFn = [ ] ;
const resolve = ( value ) => {
queueMicrotask ( ( ) => {
this . value = value;
this . state = promise_state_fulfilled;
this . successCallbackFn. forEach ( ele => ele ( value) )
} )
}
const rejected = ( err ) => {
queueMicrotask ( ( ) => {
this . reason = err;
this . state = promise_state_onRejected;
this . catchCallbackFn. forEach ( ele => ele ( err) )
} )
}
execFn ( resolve, rejected)
}
then ( execThen ) {
this . successCallbackFn. push ( execThen)
}
catch ( execCatch) {
if ( this . state === promise_state_onRejected)
execCatch ( this . reason)
}
}
const promise = new ShkPromise ( ( res, rej ) => {
res ( 123 )
} )
promise. then ( res => {
console. log ( res)
} )
promise. then ( res => {
console. log ( res)
} )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
当then是在setTimeout里时 ,将不会调用 此时需要在then函数中做个判断
then ( execThen ) {
if ( this . state === promise_state_pending) {
this . successCallbackFn. push ( execThen)
} else {
execThen ( this . value)
}
}
此时需要考虑then的返回值其实也是个promise函数 故需要将 then进行改造
push的时候将不能直接将 函数push 得用箭头函数再包裹一层 得有 try catch。当走到 catch时其实会调用 .catch的回调函数
then ( execThen ) {
return new ShkPromise ( ( res, rej ) => {
if ( this . state === promise_state_pending) {
this . successCallbackFn. push ( ( ) => {
try {
const result = execThen ( this . value)
res ( result) ;
} catch ( err) {
rej ( err)
}
} )
} else {
try {
const result = execThen ( this . value)
res ( result) ;
} catch ( err) {
rej ( err)
}
}
} )
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
其实 then调用是有两个参数的 第一个参数是成功的回调函数 第二个参数是 失败的回调函数 故此时还需要添加第二个参数
then ( execThen, execCatch ) {
return new ShkPromise ( ( res, rej ) => {
if ( this . state === promise_state_pending) {
this . successCallbackFn. push ( ( ) => {
try {
const result = execThen ( this . value)
res ( result) ;
} catch ( err) {
rej ( err)
}
} )
this . catchCallbackFn. push ( ( ) => {
try {
const reason = execCatch ( this . reason)
res ( reason) ;
} catch ( err) {
rej ( err)
}
} )
}
if ( this . state === promise_state_fulfilled) {
try {
const result = execThen ( this . value)
res ( result) ;
} catch ( err) {
rej ( err)
}
}
if ( this . state === promise_state_onRejected) {
try {
const reason = execCatch ( this . value)
res ( reason) ;
} catch ( err) {
rej ( err)
}
}
} )
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
考虑完then 需要考虑catch 其实catch很简单 只需要执行内部的then方法即可
catch也是返回一个promise 故也需要返回值
catch ( execCatch) {
return this . then ( undefined , execCatch)
}
但是我们发现如果直接调用 catch 是没有问题的 但是如果先调用 then(不传第二个参数) 再调用catch就会报错
const promise = new ShkPromise ( ( res, rej ) => {
rej ( 123 )
} )
promise. catch ( res => {
console. log ( res)
} )
promise. then ( ( ) => {
console. log ( 123 )
} ) . catch ( res => {
console. log ( res)
} )
这是因为 then 时 传入的第二个参数是undefined 故当执行 undefined()时会报错
then ( execThen, execCatch ) {
execCatch = execCatch ?? ( ( ) => {
throw this . reason
} )
... other
}
同理 当then函数中 第一个参数为undefined时肯定也会有问题
then ( execThen, execCatch ) {
execThen = execThen?? ( ( ) => {
return this . value
} )
... other
}
此时promise 大功告成 但是当 new时 promise参数中的res和rej都执行时会发现都可以执行
const promise = new ShkPromise ( ( res, rej ) => {
rej ( 123 )
res ( 222 )
} )
promise. then ( ( res ) => {
console. log ( res)
} ) . catch ( error => {
console. log ( error, '我是error' )
} )
在前面我们发现在resolve 和 rejected函数执行的时候并没有查看状态
const resolve = ( value ) => {
queueMicrotask ( ( ) => {
if ( this . state === promise_state_pending) {
this . value = value;
this . state = promise_state_fulfilled;
this . successCallbackFn. forEach ( ele => ele ( value) )
}
} )
}
const rejected = ( err ) => {
queueMicrotask ( ( ) => {
if ( this . state === promise_state_pending) {
this . reason = err;
this . state = promise_state_onRejected;
this . catchCallbackFn. forEach ( ele => ele ( err) )
}
} )
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
finally
就是在最后的时候执行 ,不管是 成功失败 最后会走finally 故将此回调函数用then调用 并且两参数都是 finally函数
finally ( execFinally) {
this . then ( execFinally, execFinally)
}
若不想将后续的参数传入 finally则将其包裹一层箭头函数
finally ( execFinally) {
this . then ( ( ) => execFinally ( ) , ( ) => execFinally ( ) )
}
大功告成,但是有个缺点 若 promise最后是失败的状态 不会将错误抛到上一层
const promise = new Promise ( ( res, rej ) => {
rej ( 222 )
} )
const promise = new ShkPromise ( ( res, rej ) => {
rej ( 222 )
} )
以下是完整代码
const promise_state_pending = 'pending'
const promise_state_fulfilled = 'fulfilled'
const promise_state_onRejected = 'onRejected'
class ShkPromise {
constructor ( execFn ) {
this . state = promise_state_pending;
this . value = null ;
this . reason = null ;
this . successCallbackFn = [ ] ;
this . catchCallbackFn = [ ] ;
const resolve = ( value ) => {
queueMicrotask ( ( ) => {
if ( this . state === promise_state_pending) {
this . value = value;
this . state = promise_state_fulfilled;
this . successCallbackFn. forEach ( ele => ele ( value) )
}
} )
}
const rejected = ( err ) => {
queueMicrotask ( ( ) => {
if ( this . state === promise_state_pending) {
this . reason = err;
this . state = promise_state_onRejected;
this . catchCallbackFn. forEach ( ele => ele ( err) )
}
} )
}
execFn ( resolve, rejected)
}
then ( execThen, execCatch ) {
execThen = execThen?? ( ( ) => {
return this . value
} )
execCatch = execCatch ?? ( ( ) => {
throw this . reason
} )
return new ShkPromise ( ( res, rej ) => {
if ( this . state === promise_state_pending) {
this . successCallbackFn. push ( ( ) => {
try {
const result = execThen ( this . value)
res ( result) ;
} catch ( err) {
rej ( err)
}
} )
this . catchCallbackFn. push ( ( ) => {
try {
const reason = execCatch ( this . reason)
res ( reason) ;
} catch ( err) {
rej ( err)
}
} )
}
if ( this . state === promise_state_fulfilled) {
try {
const result = execThen ( this . value)
res ( result) ;
} catch ( err) {
rej ( err)
}
}
if ( this . state === promise_state_onRejected) {
try {
const reason = execCatch ( this . value)
res ( reason) ;
} catch ( err) {
rej ( err)
}
}
} )
}
catch ( execCatch) {
return this . then ( undefined , execCatch)
}
finally ( execFinally) {
this . then ( ( ) => execFinally ( ) , ( ) => execFinally ( ) )
}
}
const promise = new ShkPromise ( ( res, rej ) => {
res ( 123 ) ;
} )
promise. catch ( ( err ) => {
console. log ( 'err' , err)
return 123
} ) . then ( res => {
console. log ( res)
return '999'
} ) . then ( res => {
console. log ( '000' , res)
throw '111'
} ) . finally ( ( ) => {
console. log ( 'w s finally' )
} )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139