自己实现一个Promise库
先看基本使用
const promise = new Promise((resolve, reject) => {
resolve(value)
// or reject(reason)
})
创建Promise时传入的回调函数是立即执行的,所以我们的Promise应该是这样(用ts实现)
function BDuckPromise(fn: (resolve: (value: any) => void, reject: (reason: any) => void) => any) { function resolve(value: any) { } function reject(reason: any) { } fn(resolve, reject); }
每个Promise对象都有三种生命状态:PENDING(未开始)、FULFILLED(已完成)、REJECTED(已失败)。生命状态只能是PENDING => FULFILLED 或者 PENDING => REJECTED 且一旦发生改变不可逆转。此时我们的代码是这样,具有了状态。
enum STATE {
PENDING = 0,
FULFILLED = 1,
REJECTED = 2
} function BDuckPromise(fn: (resolve:(value: any) => void, reject: (reason: any) => void) => any) {
let store = null,
state = STATE.PENDING function resolve(value: any): void {
store = value;
state = STATE.FULFILLED;
} function reject(reason: any): void {
store = reason;
state = STATE.REJECTED;
} fn(resolve, reject)
}
一个Promise对象回调中传入的值(value)或者拒因(reason)是在该示例对象的then函数中获取的
promise.then(value => {
console.log(value);
return value + 1
}, reason => {
// ....
})
then具有两个回调函数onfulfilled(用于成功时传递value)、onrejected(用于失败时传递reason)
所以我们then方法大概是长这样子
function BDuckPromise() {
this.then = (onfulfilled, onrejected) => {
if(state === STATE.PENDING) {
return
} if(state === STATE.FULFILLED) {
onfulfilled(store)
return
} if(state === STATE.REJECTED) {
onrejected(store)
return
}
}
}
但是等一下,如果我们写成这个样子当我们调用then的时候就必须要求promise的状态已经发生过改变我们才能获取到value或者reason,这个显然不是我们需要的。但是我们应该要写成什么样呢?分析一下
当我们调用then时候promise仍然处于pending状态时,我们应该怎么将value或者reason在它状态发生改变是传递出去呢?
显然,我们应该在状态发生改变时调用对应的onfulfilled或者onrejected回调。
那么我们就应该在状态为pending时将回调函数都存储起来,一旦状态改变了,就调用这些回调函数,这下就清楚了,应当在resolve或者reject中调用我们的onfulfilled或者onrejected回调
enum STATE {
PENDING = 0,
FULFILLED = 1,
REJECTED = 2
} function BDuckPromise(fn: (resolve:(value: any) => void, reject: (reason: any) => void) => any) {
let store = null,
state = STATE.PENDING,
callbacks = []; function resolve(value: any): void {
store = value;
state = STATE.FULFILLED;
callbacks.forEach(callback => {
if(callback.onfulfilled && 'function' === typeof callback.onfulfilled) {
callback.onfulfilled(store)
}
});
callbacks = null
}; function reject(reason: any): void {
store = reason;
state = STATE.REJECTED;
callbacks.forEach(callback => {
if(callback.onrejected && 'function' === typeof callback.onrejected) {
callback.onrejected(store)
}
});
callbacks = null
}; this.then = (onfulfilled, onrejected) => {
if(state === STATE.PENDING) {
callbacks.push({
onfulfilled,
onrejected
})
return
} if(state === STATE.FULFILLED) {
onfulfilled(store)
return
} if(state === STATE.REJECTED) {
onrejected(store)
return
}
};
fn(resolve, reject)
}
then函数是有返回值的,且返回的的是一个新的Promise对象,所以还得改=_=!
const promise1 = new Promise((resolve, reject) => {
resolve(1)
})
// promise2 是一个新的Promise对象
const promise2 = promise1.then(value => {
return value + 1
})
现在改成这样子
this.then = (onfulfilled, onrejected) => {
return new BDuckPromise((_resolve, _reject) => {
if(state === STATE.PENDING) {
callbacks.push({
onfulfilled,
onrejected
})
return
} if(state === STATE.FULFILLED) {
onfulfilled(store)
return
} if(state === STATE.REJECTED) {
onrejected(store)
return
}
});
}
上一个then函数中return的值会传递给下一个then中作为值
const promise1 = new Promise((resolve, reject) => {
resolve(1)
})
// promise2 是一个新的Promise对象
const promise2 = promise1.then(value => {
return value + 1
})
.then(value => {
console.log(value) // 2
})
好吧,接着改=_=
this.then = (onfulfilled, onrejected) => {
return new BDuckPromise((_resolve, _reject) => {
if(state === STATE.PENDING) {
callbacks.push({
onfulfilled,
onrejected,
_resolve,
_reject
})
return
} if(state === STATE.FULFILLED) {
const ret = onfulfilled(store)
_resolve(ret)
return
} if(state === STATE.REJECTED) {
const ret = onrejected(store)
_reject(ret)
return
}
});
} // 相应的resolve, reject也做相应的更改
function resolve(value: any): void {
store = value;
state = STATE.FULFILLED;
callbacks.forEach(callback => {
if(callback.onfulfilled && 'function' === typeof callback.onfulfilled) {
const ret = callback.onfulfilled(store)
callback._resolve(ret)
}
})
} function reject(reason: any): void {
store = reason;
state = STATE.REJECTED;
callbacks.forEach(callback => {
if(callback.onrejected && 'function' === typeof callback.onrejected) {
const ret = callback.onrejected(store)
callback._reject(ret)
}
})
}
如果then中return的是一个新的Promise则下一个then中的value或reason是这个返回的Promise中resolve或者reject中传递value或者reason
enum STATE {
PENDING = 0,
FULFILLED = 1,
REJECTED = 2
} function BDuckPromise(fn: (resolve:(value: any) => void, reject: (reason: any) => void) => any) {
let store:any = null,
state = STATE.PENDING,
callbacks:any = [] function resolve(value: any): void {
setTimeout(() => {
state = STATE.FULFILLED;
// value 是一个Promise对象
if(value && 'object' === typeof value && value.then && 'function' === typeof value.then) {
// do then
value.then(resolve, reject)
return
}
// value 不是Promise对象
store = value;
callbacks.forEach(callback => {
if(callback.onfulfilled && 'function' === typeof callback.onfulfilled) {
const ret = callback.onfulfilled(store)
callback._resolve(ret)
}
})
callbacks = []
})
} function reject(reason: any): void {
setTimeout(() => {
state = STATE.REJECTED;
// value 是一个Promise对象
if(reason && 'object' === typeof reason && reason.then && 'function' === typeof reason.then) {
reason.then(resolve, reject)
return
}
// value 不是Promise对象
store = reason;
callbacks.forEach(callback => {
if(callback.onrejected && 'function' === typeof callback.onrejected) {
const ret = callback.onrejected(store)
callback._reject(ret)
}
})
callbacks = []
}, 0)
} this.then = (onfulfilled, onrejected) => {
return new BDuckPromise((_resolve, _reject) => {
if(state === STATE.PENDING) {
callbacks.push({
onfulfilled,
onrejected,
_resolve,
_reject
})
return
} if(state === STATE.FULFILLED) {
const ret = onfulfilled(store)
_resolve(ret)
return
} if(state === STATE.REJECTED) {
const ret = onrejected(store)
_reject(ret)
return
}
});
} fn(resolve, reject)
}
export default BDuckPromise;
还有reject的处理,目前是不合规范的
大概就是这样,不搞了
最新文章
- 逆向工程学习第四天--Windows栈溢出保护机制(GS)原理及绕过测试
- PHP中函数sprintf .vsprintf (占位符)
- MLUtils.loadLibSVMFile
- POJ 1300 欧拉通路&;欧拉回路
- SharePoint 2007 文档库中的文档添加评论功能
- 火狐l浏览器所有版本
- Jenkins+Maven+Gitlab+Tomcat 自动化构建打包、部署
- 【转】CefSharp语言(Locales)本地化问题
- xen 基础命令学习
- [Wc]Dface双面棋盘()
- 电影编码JPEG2000与H.264
- PL/SQL编码规范的一些建议
- docker之compose 编排项目
- HDU 3018 Ant Trip (欧拉回路)
- Linux环境下 多线程下载 (Python 实现版)
- spring cloud 报错Error creating bean with name 'hystrixCommandAspect' ,解决方案
- spring+ehcache实战--性能优化之道
- 真机远程页面调试工具spy-debugger 3.x:集成weinre+AnyProxy,页面调试+抓包。调试生产HTTPS页面。
- ubuntu-未信任的应用程序启动器-XX-Net.desktop
- python学习笔记(二十四)继承与封装