1、基本功能
1、new一个example实例的时候,通过a函数使得该实例获得一个执行成功后的值1
2、在使用then的时候传递一个函数参数on(re){}进去,在then内部会将上一步执行成功的值作为实参传进这个函数on,从而实现在执行一个函数后将结果传给它的回调函数的功能。
class example{
constructor(fc){
this.p=null
fc(this.a.bind(this))//传进来一个函数参数fc(a){a(1)},用this.a.bind(this)做实参,执行
//该函数,这时this.p被赋值
}
a(p1){
this.p=p1
}
then(on){
on(this.p)//传进来一个函数参数on(re){console.log(re)},用this.p做实参,执行该函数
console.log(on)//re=>console.log(re)
}
}
var s1=new example(a=>a(1))
s1.then(re=>console.log(re))//1
3、状态的设置,为了避免混淆函数执行(因为promise中有执行成功和失败两种情况),添加一个状态变量。
class example{
constructor(fc){
this.p=null
this.s='p';
fc(this.a.bind(this))
}
a(p1){
if(this.s=='p'){
this.p=p1
this.s='f'
}
}
then(on){
if(this.s=='f'){
on(this.p)
console.log(on)//re=>console.log(re)
}
}
}
var s1=new example(a=>a(1))
s1.then(re=>console.log(re))//1
2、异步实现
1、如下代码,如果能和promise一样实现异步操作,那么打印顺应应该是11 22 33 1,但是我们并没有实现异步,所以实际上打印的是11 22 1 33
console.log('11')
var s1=new example(a=>{
console.log('22');
a(1)
})
s1.then(re=>console.log(re))//1
console.log('33')
2、要实现11 22 33 1很容易,在then函数中使用settimeout函数实现异步即可,如下代码即可实现
11 22 33 1
then(on){
if(this.s=='f'){
setTimeout(()=>{
on(this.p)
})
}
}
3、但是如果在如下代码中使用settimeout呢?结果是11 22 33,发现1不见了,也就是then的函数没有打印出来
var s1=new example(a=>{
console.log('22');
setTimeout(()=>{
a(1)
})
})
4、如果我把then中的状态判断注释掉,发现打印的是11 22 33 1,成功了?说明是状态的流程出来问题,由于使用了settimeout函数,我们会先执行了后面的then,但是这个时候执行then肯定是不行的,因为a函数还没有执行,导致状态还是p(等待),所以then啥也没有。
解决办法就是在执行then时如果是p状态,就将要执行的on函数保存起来,等一会a函数执行完再执行这个on,下面代码正确执行了11 22 33 1
class example{
constructor(fc){
this.p=null
this.s='p';
this.callbackfc=[];
fc(this.a.bind(this))
}
a(p1){
if(this.s=='p'){
this.p=p1
this.s='f'
this.callbackfc.forEach(callback=>{callback(p1)})
}
}
then(on){
if(this.s=='p'){
this.callbackfc.push(on);
}
if(this.s=='f'){
setTimeout(()=>{
on(this.p)
})
}
}
}
console.log('11')
var s1=new example(a=>{
console.log('22');
setTimeout(()=>{
a(1)
})
})
s1.then(re=>console.log(re))//1
console.log('33')
5、最后一个问题,在实例s1的异步操作中,a函数总是最后执行的,也就是说在下面代码中应该是11 22 33 44 1,但是实际上a(1)要在console.log('44')前面执行,为了实现a(1)最后执行,需要在a函数中添加一个settimeout,完美实现
console.log('11')
var s1=new example(a=>{
console.log('22');
setTimeout(()=>{
a(1)
console.log('44')
})
})
s1.then(re=>console.log(re))//1
console.log('33')
a(p1){
setTimeout(()=>{
if(this.s=='p'){
this.p=p1
this.s='f'
this.callbackfc.forEach(callback=>{callback(p1)})
}
})
}
3、链式调用
then函数返回一个example实例即可
then(on){
return new example(a=>{
if(this.s=='p'){
this.callbackfc.push(on);
}
if(this.s=='f'){
setTimeout(()=>{
on(this.p)
})
}
})
}
4、总结
因为原生promise构造函数有两个函数参数resolve,reject,本文中为了方便理解只写了一个,多一个参数实际上也是多一个情况而已,实际上本质上没有区别;下面附上完整的自写代码
class ownPromise{
static status;
constructor(resolve,reject){
this.result=null;
this.status='pending';
this.rescallbackfc=[];
this.rejcallbackfc=[];
resolve(this.resolve.bind(this));
reject(this.reject.bind(this));
}
resolve(result){
setTimeout(()=>{
if(this.status=='pending'){
this.status='fulfilled';
this.result=result;
this.rescallbackfc.forEach(callback=>{callback(result)})
}
})
}
reject(result){
setTimeout(()=>{
if(this.status=='pending'){
this.status='rejected';
this.result=result;
this.rejcallbackfc.forEach(callback=>{callback(result)})
}
})
}
then(onfulfilled,onrejected){
return new ownPromise(resolve=>{
if(this.status=='pending'){
this.rescallbackfc.push(onfulfilled);
this.rejcallbackfc.push(onrejected);
}
if(this.status=='fulfilled'){
setTimeout(()=>{
onfulfilled(this.result);})
}},reject=>{
if(this.status=='pending'){
this.rescallbackfc.push(onfulfilled);
this.rejcallbackfc.push(onrejected);
}
if(this.status=='rejected'){
setTimeout(()=>{
onrejected(this.result);})
}
})
}
}
console.log('1')
let ownpromise1=new ownPromise(resolve=>
{
console.log('2')
setTimeout(()=>{
resolve('椰奶');
})
},reject=>{}
)
let ownpromise2=new ownPromise(resolve=>
{},reject=>{
setTimeout(()=>{
reject('没有椰奶');}
)}
)
ownpromise1.then(result=>{console.log(result)},result=>{})
.then()
ownpromise2.then(result=>{},result=>{console.log(result)})
console.log('3')