实现自己的Promise(1)

20 篇文章 0 订阅
5 篇文章 0 订阅

一直以来都对Promise的实现有浓厚的兴趣、感觉很好玩。很想搞清楚他的原理是什么,而最好的办法莫过于写一个自己的Promise了。
首先我们需要看一下Promise的基本使用方式是什么样子的。

let testPromise =new Promise((resolve,reject)=>{
  setTimeout(()=>{
    resolve('ok')
  },2000)
})
testPromise.then((res)=>{
  console.log(res);
})

可以观测到,在2s后,将会在控制台打印出来ok
首先,我们要确定的最关键的一点是,Promise没有解决回调函数的问题,可以看到我们的执行方案依旧是根据回调函数来解决的,但是我们的方案更加的优雅一点、其次、如果我们注释后面的代码执行以下代码

let testPromise =new Promise((resolve,reject)=>{
  console.log('promise');
  setTimeout(()=>{
    console.log('ok');
    resolve('ok')
  },2000)
})
// testPromise.then((res)=>{
//   console.log(res);
// })

会很快的打印出来 promise 在过了2s后打印出来OK。可见。Promise是在new的时候就执行了,而不是在then的时候。
同时我们观测我们的代码可以有以下的结论

  1. Promise是一个类,需要使用new创建
  2. Promise在new的时候接收一个参数,该参数是一个函数executor
  3. executor接收两个参数,这两个参数也是一个函数,分别为resolve跟reject
  4. Promise生成的对象里面有一个属性是then。它接收两个回调函数onFulfilled跟onRejected
  5. 如果存在异步的情况,那么then中回调函数不会立即执行、可见必有缓存机制
  6. 在resolve结束之后执行onFulfilled,在reject函数之后执行onRejected,并且只会执行其中一个函数

那么我们按照这个思路来写一个Promise吧
1.

class MyPromise{
 
}

MyPromise应该是一个类
2.

class MyPromise{
  constructor(exector){
    exector(resolve,reject)
  }
}

可是我们的resolve跟reject在哪里呢?
很明显无法接受外部的参数,那么就只能是我们MyPromise内部的函数了
3.

class MyPromise{
  constructor(exector){
    exector(resolve,reject)
  }
  resolve(){

  }
  reject(){
    
  }
}
class MyPromise{
  constructor(exector){
    exector(resolve,reject)
  }
  resolve(){

  }
  reject(){

  }
  then(onFulfilled,onRejected){

  }
}
class MyPromise{
  constructor(exector){
    this.onFulfilledCallbacks=[]
    this.onRejectedCallbacks=[]
    exector(resolve,reject)
  }
  resolve(){

  }
  reject(){

  }
  then(onFulfilled,onRejected){
    this.onFulfilledCallbacks.push(onFulfilled)
    this.onRejectedCallbacks.push(onRejected)
  }
}

在resolve之后执行onFulfilled 在这里我们就需要引入状态机制了。我们知道Promise是有状态的,而resolve其实就是把Promise的状态从pedding变成fulfilled而reject则是变成rejected

class MyPromise{
  constructor(exector){
    this.onFulfilledCallbacks=[]
    this.onRejectedCallbacks=[]
    this.state='pedding'
    this.value=null //成功的回调值
    this.reason=null //成功的回调值

    exector(resolve,reject)
  }
  resolve(value){
    if(this.state==='pedding'){
      this.state='fulfilled'
      this.value=value
      this.onFulfilledCallbacks.forEach(fn=>fn(value))
    }
  }
  reject(reason){
    if(this.value==='pedding'){
      this.state='rejected'
      this.reason=reason
      this.onRejectedCallbacks.forEach(fn=>fn(reason))
    }
  }
  then(onFulfilled,onRejected){
    this.onFulfilledCallbacks.push(onFulfilled)
    this.onRejectedCallbacks.push(onRejected)
  }
}

我们可以测试一下

let testPromise =new MyPromise((resolve,reject)=>{
  setTimeout(()=>{
    resolve('ok')
  },2000)
})
testPromise.then((res)=>{
  console.log('then');
  console.log(res);
})

可以发现一些问题因为执行环境的问题,所以this的指向是有问题的,我们可以手动绑定一下


class MyPromise{
  constructor(exector){
    this.onFulfilledCallbacks=[]
    this.onRejectedCallbacks=[]
    this.state='pedding'
    this.value=null //成功的回调值
    this.reason=null //成功的回调值

    exector(this.resolve.bind(this),this.reject.bind(this))
  }
  resolve(value){
    if(this.state==='pedding'){
      this.state='fulfilled'
      this.value=value
      this.onFulfilledCallbacks.forEach(fn=>fn(value))
    }
  }
  reject(reason){
    if(this.state==='pedding'){
      this.state='rejected'
      this.reason=reason
      this.onRejectedCallbacks.forEach(fn=>fn(reason))
    }
  }
  then(onFulfilled,onRejected){
    this.onFulfilledCallbacks.push(onFulfilled)
    this.onRejectedCallbacks.push(onRejected)
  }
}

这样实际上执行结果就符合我们的预期了
但是其实还是有些问题的

  1. 不是很符合PromiseA+的规范
  2. reject跟resolve函数其实不应该被返回
  3. 是否在一开始的时候就存在fulfilled状态呢?
    对于第三个问题,我们注意到Promise被执行的时候并不是在then的时候而是在new的时候,也就是说会有可能出现这种情况
setTimeout(()=>{
  testPromise.then((res)=>{
    console.log('then');
    console.log(res);
  })
},3000)

观测到控制台无打印,因为此时已经是fulfilled状态了
因此我们必须把,而因此没有执行then的缘故,所以并没在callbacks里面添加函数,因此我们要在then里面设置一下状态改变

下面给出一版本更规范一点的实现

class MyPromise{
  constructor(exector){
    this.onFulfilledCallbacks=[]
    this.onRejectedCallbacks=[]
    this.state='pedding'
    this.value=null //成功的回调值
    this.reason=null //成功的回调值
    let resolve=(value)=>{
      if(this.state==='pedding'){
        this.state='fulfilled'
        this.value=value
        this.onFulfilledCallbacks.forEach(fn=>fn(this.value))
      }
    }
    let reject=(reason)=>{
      if(this.state==='pedding'){
        this.state='rejected'
        this.reason=reason
        this.onRejectedCallbacks.forEach(fn=>fn(this.reason))
      }
    }

    exector(resolve,reject)
  }
  then(onFulfilled,onRejected){
    if(this.state==='fulfilled'){
      onFulfilled(this.value)
    }
    if(this.state==='rejected'){
      onRejected(this.reason)
    }
    if(this.state==='pedding'){
      this.onFulfilledCallbacks.push(onFulfilled)
      this.onRejectedCallbacks.push(onRejected)
    }
  }
}
let testPromise =new MyPromise((resolve,reject)=>{
  setTimeout(()=>{
    resolve('ok')
  },2000)
})
testPromise.then((res)=>{
  console.log('then');
  console.log(res);
})

关于PromiseA+规范我们可以参考

https://promisesaplus.com/

这样我们就实现了一个基本具有Promise样子的MyPromise。但是。回到开头我们提到了Promise依旧是依靠回调函数来执行的,这个样子跟我们使用回调函数的区别不是很大,为什么还要写Promise呢?原因在于Promise的精髓。链式调用
也就是

let testPromise =new Promise((resolve,reject)=>{
  setTimeout(()=>{
    resolve('ok')
  },2000)
})
testPromise.then((res)=>{
  console.log(res);
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      resolve('ok2')
    },2000)
  })
}).then((res)=>{
  console.log(res);
})

下一篇文章我们将会研究一下Promise是怎么实现链式调用的

在 JavaScript ,可以通过实现一个类来实现 Promise 的功能。 下面是一个简单的实现示例: ``` class MyPromise { constructor(executor) { this.status = "pending"; this.value = undefined; this.reason = undefined; this.onResolvedCallbacks = []; this.onRejectedCallbacks = []; let resolve = (value) => { if (this.status === "pending") { this.status = "fulfilled"; this.value = value; this.onResolvedCallbacks.forEach(fn => fn()); } }; let reject = (reason) => { if (this.status === "pending") { this.status = "rejected"; this.reason = reason; this.onRejectedCallbacks.forEach(fn => fn()); } }; try { executor(resolve, reject); } catch (e) { reject(e); } } then(onFulfilled, onRejected) { onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value; onRejected = typeof onRejected === "function" ? onRejected : reason => { throw reason; }; let promise2 = new MyPromise((resolve, reject) => { if (this.status === "fulfilled") { setTimeout(() => { try { let x = onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }); } if (this.status === "rejected") { setTimeout(() => { try { let x = onRejected(this.reason); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }); } if (this.status === "pending") { this.onResolvedCallbacks.push(() => { setTimeout(() => { try { let x = onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }); }); this.onRejectedCallbacks.push(() => { setTimeout(() => { try { let x = onRejected(this.reason); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }); }); } }); return promise2; } } function resolvePromise(promise2, x, resolve, reject) { if (promise2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值