promise简单实现

20 篇文章 0 订阅
10 篇文章 0 订阅

Promise含义

Promise是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6将其写进了语言标准,统一了用法,原生提供了Promise对象。

所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise是一个对象,从它可以获取异步操作的消息。Promise提供统一的API,各种异步操作都可以用同样的方法进行处理。

Promise特点

Promise对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称Fulfilled)和Rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。

Promise实现

实现思路:将then方法中的第一个参数 (onResolve) 依次塞进成功队列 resolveList 中,当 resolve(value) 时,遍历 resolveList 中的事件,将 value 传递并更新至最后一个then方法结束;若then方法中有第二个参数 (onReject) 且 rejectCallback 为 null 时,将 onReject 拷贝到 rejectCallback ,这样就实现了 reject(error) 时只会将 error 传递到第一个出现 onReject 参数的then方法里面。

因为我是在node环境写的,所以这里就直接使用es6的class实现promise,底层依然是构造函数实现:

class MyPromise {
  constructor(executor) {
    let self = this;
    this.status = 'pending';         // promise状态, 作用:避免执行多次resolve
    this.data = null;                // 传递的数据
    this.resolveList = [];           // 成功列表
    this.rejectCallback = null;      // 失败回调

    // 成功回调
    function resolve(data) {
      if (self.status === 'pending') {
        self.status = 'resolved';
        self.data = data;

        self.resolveList.forEach(callback => {
          // 更新回调列表传递的值
          let newData = callback(self.data);
          self.data = newData;
        })
      }
    }

    // 失败回调
    function reject(reason) {
      if (self.status === 'pending') {
        self.status = 'rejected';
        self.data = reason;
        self.rejectCallback(reason)
      }
    }

    executor(resolve, reject)
  }

  then(onResolve, onReject) {
    this.resolveList.push(onResolve);

    // 检查触发then时是否有填写第二个参数, 若有则error将不返回错误到catch方法中,直接返回到第一个出现reject回调的then方法中
    if (onReject && !this.rejectCallback) { 
      this.rejectCallback = onReject
    }

    // 返回实例使它可以继续使用then方法
    return this
  }

  catch(callback) {
    // 判断前面的then调用时是否填写了第二个参数
    if (!this.rejectCallback) {
      this.rejectCallback = callback;
    }
  }
}

这样就简单的实现了Promise,我们可以来测试一下:

let test = new MyPromise((resolve, reject) => {
  console.log('三秒后出结果...')
  let num = Math.random();

  setTimeout(() => {
    num > 0.5 ? resolve(num) : reject(num)
  }, 3000)

}).then(value => {
  console.log('then1:', value)
  return value + 1

}).then(value => {
  console.log('then2:', value)

}).catch(err => {
  console.log('出错了:', err)
})

node运行后可能得到的结果是:
三秒后出结果...
then1: 0.7013671932574768        // 这个值是随机数
then2: 1.7013671932574768

也可能是:
三秒后出结果...
出错了: 0.11785923049044666

这时候我们去掉setTimeout看看结果是什么:

这时候我们就会看到没有出现结果,这是因为不使用定时器直接执行会导致 resolve() 在执行的时候 then 方法还没有执行,也就是 resolveList 长度为0,这是由于Promise回调函数延迟绑定导致的,Promise使用了微任务 queneMicrotask 解决这个问题,这里我们就用宏任务的定时器模拟微任务,修改了 resolve 和 reject 方法:

function resolve(data) {
  // 用宏任务代替queueMicrotask模拟promise微任务
  setTimeout(() => {
    if (self.status === 'pending') {
      self.status = 'resolved';
      self.data = data;

      self.resolveList.forEach(callback => {
        // 更新回调列表传递的值
        let newData = callback(self.data);
        self.data = newData;
      })
    }
  })
}

// 失败回调
function reject(reason) {
  // 用宏任务代替queueMicrotask模拟promise微任务
  setTimeout(() => {
    if (self.status === 'pending') {
      self.status = 'rejected';
      self.data = reason;
      self.rejectCallback(reason)
    }
  })
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值