剖析promise

一、分析promise之前,先了解清楚EventLoop

事件循环机制从整体上告诉了我们 JavaScript 代码的执行顺序 Event Loop即事件循环。是指浏览器或Node的一种解决javaScript单线程运行时不会阻塞的一种机制,也就是我们经常使用异步的原理。
先执行 Script 脚本,然后清空微任务队列,然后开始下一轮事件循环,继续先执行宏任务,再清空微任务队列,如此往复。

二、宏任务和微任务

因为js的一大特点是单线程,为了协调事件,交互渲染等等行为,防止主线程的阻塞,js有两种任务的执行模式:同步模式和异步模式。

异步任务下主要分为宏任务和微任务。ES6规范中

  • 宏任务(Macrotask)包含:
  1. script(整体代码),
  2. setTimeout
  3. setInterval
  4. I/O,UI交互事件
  5. postMessage
  6. MessageChannel
  7. setImmediate(Node.js 环境)
  • 微任务(Microtask)包含:
  1. Promise.then
  2. Object.observe
  3. MutationObserver
  4. process.nextTick(Node.js 环境)。

三、promise的基础实现

1、promise的基本功能
const promise = new Promise((resolve, reject) => {
  resolve('success')
  reject('err')
})

promise.then(res => {
 console.log('resolve', res)
}, err => {
 console.log('reject', err)
})
2、分析基本原理
  • 一个Promise的当前状态必须为以下三种状态中的一种:等待态(Pending)、执行态(Fulfilled)和拒绝态(Rejected)。
  • 状态的改变只能是单向的,且变化后不可在改变。
  • 一个promise对象接收的是一个callback,这个callback接收两个参数(resolve,reject),当我们在callback内执行resolve或reject的时候,就会调用Promise内定义的
    resolve和reject函数,然后,resolve和reject函数会改变Promise的状态。

定义FsPromise,并定义参数:

function FsPromise (cb) {
  //保存this值
  var _this = this
  //记录状态null为pending ,true为resolved, false为reject
  var status = null
  //记录resolve的参数
  var param = null

  //执行传入的callback并改变promise对象状态
  cb(resolve,reject)

  // resolve方法
  function resolve(data) {}
  //reject方法
  function reject(err) {}
}
3、完善resolve和reject函数

但是如果promise的状态为pending,由于原始promise的状态是无法动态获取的,因此就需要在执行状态改变的时候同时执行onFulfilled和onRejected方法。

我们可以把这个方法放在原始promise对象的resolve和reject方法中执行。所以要在promise的对象定义中添加四个参数,分别记录onFulfilled和onRejected,以及then方法返回的新promise对象的resolve和reject。

然后如果执行then方法的时候promise对象的状态为pending的话,就将上述四个参数记录起来。

function FsPromise (cb) {
  //保存this值
  var _this = this
  //记录状态null为pending ,true为resolved, false为reject
  var status = null
  //记录resolve的参数
  var param = null

  var nextResolve = null;
  var nextReject = null;
  // 记录then方法的参数,onFulfilled和onRejected
  var asynconFulfilled = null;
  var asynconRejected = null;

  //执行传入的callback并改变promise对象状态
  cb(resolve,reject)

  // resolve方法
  function resolve(data) {
    //改变状态
    status = true
    param = data
    nextResolve(asynconFulfilled(param))
  }
  //reject方法
  function reject(err) {
    status = false
    param = err
    nextReject(asynconRejected(param))
  }
}
4、then的简单实现
  • then方法接收两个可选的参数(onFulfilled, onRejected)
  • then方法传进来的参数必须是函数
this.then = function(onFulfilled, onRejected){
  // 返回一个新的promise对象
  return new _this.constructor(function(resolve,reject){
    // 判断异步代码是否执行完毕(是否resolve或reject)
    // 若执行完毕就在then方法中立即执行,否则将四个参数记录下来,等待status就绪后再执行doAsyn*函数
    // onFulfilled, onRejected这两个函数要在promise的状态变为pending或resolved的时候才能分别执行
    if(status === true){
      // param是promise对象完成后的结果
      resolve(onFulfilled(param))
    }else if(status === false){
      reject(onRejected(param))
    }else{
      // 执行完毕
      nextResolve = resolve;
      nextReject = reject;
      asynconFulfilled = onFulfilled;
      asynconRejected = onRejected;
    }
  })
}
5、加入异步逻辑
// resolve方法
  function resolve(data) {
    status = true
    param = data
    // nextResolve(asynconFulfilled(param))
    if(nextResolve){
      doAsynconFulfilled(asynconFulfilled,nextResolve,nextReject);
    }
  }
  //reject方法
  function reject(err) {
    status = false
    param = err
    // nextReject(asynconRejected(param))
    if(nextReject){
      doAsynconRejected(asynconRejected,nextResolve,nextReject);
    }
  }

  // 主要核心代码
  function doAsynconFulfilled(onFulfilled,resolve,reject){
    setTimeout(function(){
      // 判断onFulfilled是否为function
      if(typeof onFulfilled === 'function'){
        // 执行onFulfilled方法获取返回值promise()
        let promise = onFulfilled(param);
        // 如果promise为undefined 则执行 if内容
        // 如果promise为MyPromise 对象 则执行 else if内容
        // 如果promise为非MyPromise 对象 执行 else
        if(promise === undefined){
          resolve(param);
        }else if(promise.constructor === _this.constructor){
          // 等待传递进来的promise对象执行完毕,然后根据传递进来的promise对象的状态执行resolve或reject
          Promise.then(function(param){
            resolve(param);
          },function(param){
            reject(param);
          })
        }else{
          // 执行then方法返回的对象的resolve
          resolve(promise);
        }
      }else{
        // 传递参数
        resolve(param)
      }
    },0)
  }

  // 同理doAsynconFulfilled
  function doAsynconRejected(onRejected,resolve,reject){
    setTimeout(function(){
      if(typeof onRejected === 'function'){
        let promise = onRejected(param);
        if(promise === undefined){
          reject(param);
        }else if(promise.constructor === _this.constructor){
          Promise.then(function(param){
            resolve(param);
          },function(param){
            reject(param);
          })
        }else{
          reject(promise)
        }
      }else{
        // 传递错误信息
        reject(param);
      }
    },0)
  }

将then方法中执行的resolve方法和reject方法换成异步方法:

  • doAsynconFulfilled(onFulfilled, resolve, reject)
  • doAsynconRejected(onRejected, resolve, reject)
6、使用上述代码,执行基本案例
const promise = new FsPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('success')
  }, 2000); 
})

promise.then(value => {
  console.log('resolve', value)
}, reason => {
  console.log('reject', reason)
})

// 执行结果为resolve success
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值