Promise详解和手写Promise

定义

  • promise:承诺,许诺
  • Promise是异步编程的一种实现方案,比起传统的解决方案(回调函数和事件),更合理,更易于维护,解决了异步回调地狱。
  • 一个Promise就是一个对象,它代表了一个异步操作最终完成或者失败。
  • Promise对象用于异步操作,它表示一个尚未完成且预计未来完成的异步操作。

JavaScript的异步和回调

  • 1、JavaScript的执行环境是单线程的。所谓单线程,就是指JavaScript引擎中负责解释和执行JavaScript代码的线程只有一个,也就是一次只能完成一项任务,这个任务执行完成后才能执行下个任务,它会阻塞其他任务,这个任务可以成为主线程。但实际上还有其他线程(事件触发线程,ajax请求线程)。
  • 2、同步模式。既上述所说的单线程模式,一次只能执行一个任务,函数调用后需要等待函数执行结束并且返回结果,才会去执行下一个函数。如果这个任务执行的时间长,则会阻塞下个任务的执行。
var msg = "this is msg"
while(true)
cosnole.log(msg) // 不会执行
  • 3、异步模式。既与同步模式相反,可以一起执行多个任务。setTimeout(()=>{},1000)是典型的异步执行任务。
setTimeout(function() {
  console.log('task A');
}, 0);
  console.log('task B');
//先输出taskB 在输出taskA
//因为同步任务先于异步任务执行,哪怕定时器的延时时间是0s
  • 4、回调函数。在异步任务完成以后,我们需要获取处理后的结果,通常,我们可以将这个函数先定义,存储在内存中,将其当做参数传入之前的异步操作函数中,等异步操作结束,就会调用执行这个函数,这个函数就叫做回调函数(callback)。
function fn(cb) {
  var a = 'aa'
  setTimeout(() => {
    a = 'change a'
    cb && cb(a)
  }, 1000)
}

fn(function(v){
  console.log(v)
})
  • 5、在文件读取,资源请求都是异步的,我们都可以通过回调来获取异步的结果,但这样又会造成函数回调层次太深,造成回调地狱。
const fs = require('fs')
fs.readFile('./a.txt',(data,error)=>{
  if(data){
    fs.readFile('./b.txt',(data,error)=>{
      fs.readFile('./c.txt',(data,error)=>{
        fs.readFile('./d.txt',(data,error)=>{
          fs.readFile('./e.txt',(data,error)=>{
      
          })
        })
      })
    })
  }
})

Promise的基本用法

//许下一个承诺
let flag = true
let  promise = new Promise((resolve,reject)=>{
  if(flag){
    reject('error') //失败的回调
  }else{
    resolve('success')  //成功的回调
  }
})
// 执行这个承诺 .then
promise.then(data=>{
  console.log(data)
}).catch(error=>{
  console.log(error)
}).finally(()=>{
  console.log('finally')
})

Promise.all

Promise的静态方法,该方法接受一个Promise数组,数组内所有的任务同时执行,只有所有的任务执行完毕才将pending转换成fulfilled

let pArr = []
let p1 = new Promise((resolve,reject)=>{

})
pArr.push(p1)
let p2 = new Promise((resolve,reject)=>{

})
pArr.push(p2)
Promise.all(pArr).then(()=>{})

Promsie.race

race也是Promise的静态方法,用法与all()类似,也是接收一个Promise数组,不同点是all()方法是等数组中的所有任务同时执行,且所有任务执行完毕才将状态由pedding转为fulfilled,race()方法是数组中的所有任务同时执行,有一个任务执行完毕时,就将状态由pedding转为fulfilled。

手动实现Promise

简易版

function MPromise() {
  let cb = arguments[0]
  let self = this
  this.msg = ''
  this.status = 'pending'
  cb(
    function() {
      self.status = 'resolve'
      self.msg = arguments[0]
    },
    function() {
      self.status = 'reject'
      self.msg = arguments[0]
    }
  )
}
MPromise.prototype.then = function() {
  if (this.status == 'resolve') {
    arguments[0](this.msg)
  }
  if (this.status == 'reject' && arguments[1]) {
    arguments[1](this.msg)
  }
}
//测试代码
let isFlag = false
let p = new KPromise((resolve, reject) => {
  if (isFlag) {
    resolve('success')
  } else {
    reject('error')
  }
})
p.then(
  data => {
    console.log(data)
  },
  error => {
    console.log(error)
  }
)

完整版

/* ----------------------------------------------------------------------------
 * Promise 完整版
 --------------------------------------------------------------------------- */
 const states = {
  PENDING  : 'pending',
  FULFILLED: 'fulfilled',
  REJECTED : 'rejected'
}

class Promise {
  /**
   * [ 构造函数 ]
   * @param  {[Function]} excurtor [执行函数]
   * @return {[Undefined]} undefined
   */
  constructor (excurtor) {
      let self = this;

      this.status      = states.PENDING; // 当前状态
      this.value       = undefined;      // 成功的内容
      this.reason      = undefined;      // 失败的原因
      this.onFulfilled = [];             // 存储成功回调
      this.onRejected  = [];             // 存储失败回调

      // 成功方法
      function resolve (value) {
          let onFulfilled = self.onFulfilled;

          // 判断状态是否为pending,只有此状态时,才可以发生状态改变
          if (self.status === states.PENDING) {
              self.status = states.FULFILLED;
              self.value = value;

              if (onFulfilled.length) {
                  onFulfilled.forEach(fn => {
                      fn();
                  });
              }
          }
      }

      // 失败方法
      function reject (reason) {
          let onRejected = self.onRejected;

          // 判断状态是否为pending,只有此状态时,才可以发生状态改变
          if (self.status === states.PENDING) {
              self.status = states.REJECTED;
              self.reason = reason;

              if (onRejected.length) {
                  onRejected.forEach(fn => {
                      fn()
                  });
              }
          }
      }

      // 立即调用执行函数,并捕获异常
      try {
          excurtor(resolve, reject);
      } catch (e) {
          reject(e); // 捕获到执行函数异常后,直接执行失败回调
      }
  }

  /**
   * [ 实例方法: then ]
   * @param  {[Function]} onFulfilled [成功回调]
   * @param  {[Function]} onRejected  [失败及异常回调]
   * @return {[Object]}  promise2
   */
  then (onFulfilled, onRejected) {
      // 补全参数,实现往下传递
      onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
      onRejected = typeof onRejected === 'function' ? onRejected : error =>{ throw error };

      let self = this;
      let promise2;

      promise2 = new Promise((resolve, reject) => {
          // 状态已改变为成功时,则立即执行
          if (self.status === states.FULFILLED) {
              setTimeout(() => { // 此定时器确保回调方法在异步中执行的,也方便进行promiseA+规范测试
                  // try catch 用来捕获回调方法中抛出的异常
                  try {
                      let x = onFulfilled(self.value);
                      resolvePromise(promise2, x, resolve, reject);
                  } catch (e) {
                      reject(e);
                  }
              });
          }

          // 状态已改变为失败时,则立即执行
          if (self.status === states.REJECTED) {
              setTimeout(() => { // 同上
                   // 同上
                  try {
                      let x = onRejected(self.reason);
                      resolvePromise(promise2, x, resolve, reject);
                  } catch (e) {
                      reject(e);
                  }
              }, 0);
          }

          // 处理异步情况,先存在起来,等状态改变再执行相应回调
          if (self.status === states.PENDING) {
              self.onFulfilled.push(() => {
                  setTimeout(() => {  // 同上
                       // 同上
                      try {
                          let x = onFulfilled(self.value);
                          resolvePromise(promise2, x, resolve, reject);
                      } catch (e) {
                          reject(e);
                      }
                  }, 0);
              });
              self.onRejected.push(() => {
                  setTimeout(() => {  // 同上
                       // 同上
                      try {
                          let x = onRejected(self.reason);
                          resolvePromise(promise2, x, resolve, reject);
                      } catch (e) {
                          reject(e);
                      }
                  }, 0);
              });
          }
      });

      return promise2;
  }

  /**
   * [ 实例方法:catch ]
   * @param  {[Function]} onRejected [失败及异常回调]
   * @return {[Object]}   promise
   */
  catch (onRejected) {
      return this.then(null, onRejected);
  }

  /**
   * [ 静态方法(由类调用):all ]
   * @param  {[Array]} promises [由promise组成的数组]
   * @return {[Object]} promise
   */
  static all (promises) {
      let res = [];
      let count = 0;
      let length = promises.length;

      return new Promise((resolve, reject) => {
          promises.forEach((promise, index) => {
              promise.then(
                  value => {
                      res[index] = value;
                      if (++count === length) {
                          resolve(res);
                      }
                  },
                  reject
              );
          });
      });
  }

  /**
   * [ 静态方法(由类调用)race ]
   * @param  {[Array]} promises [由promise组成的数组]
   * @return {[Object]} promise
   */
  static race (promises) {
      return new Promise((resolve, reject) => {
         promises.forEach(promise => {
             promise.then(resolve, reject);
         })
      });
  }
}

function resolvePromise(promise2, x, resolve, reject) {
   // 自己不能等待自己的状态改变
   if (promise2 === x) {
       return reject(new TypeError('循环引用'));
   }

   let called; // 标识位,要么成功,要么失败;
   let typeX = typeof x;

   // 判断x的类型是否为对象或者函数且不为null
   if (x !== null && (typeX === 'object' || typeX === 'function')) {
       try {
           let then = x.then; // 获取then方法; 此处的try用于防止第三方库中获取值会抛错

           if (typeof then === 'function') { // 说明返回的是promise事例
               // 执行then方法,并将this指向x
               then.call(x, y => {
                   if (called) return;
                   called = true;
                   // 如果返回的还是promise, 则将会继续递归调用
                   resolvePromise(promise2, y, resolve, reject);
               }, e => {
                   if (called) return;
                   called = true;
                   reject(e);
               });
           } else { // x为变通对象时,直接成功
               resolve(x);
           }
       } catch (e) {
           if (called) return;
           called = true;
           reject(e);
       }
   } else {
       resolve(x);
   }
}

// 为了方便promiseA+规范测试
Promise.defer = Promise.deferred = function () {
   let dtd = {};
   dtd.promise = new Promise((resolve, reject) => {
       dtd.resolve = resolve;
       dtd.reject = reject;
   });
   return dtd;
};


module.exports = Promise;



// 测试例子 ---------------------------------------------------------------------
let promise = new Promise((resolve, reject) => {
  resolve(1000);
  //reject(100);
});

promise
.then(
  value => {
      console.log('then:', value);
      return new Promise((resolve, reject) => {
          //resolve(199);
          reject('error123');
      });
  },
  reason => console.log(`fail: ${ reason }`)
)
.then(
  value => console.log(value),
  reason => console.log(`fail: ${ reason }`)
);

Promise.all([
   new Promise((resolve, reject) => {
       resolve(1);
   }),
   new Promise((resolve, reject) => {
       setTimeout(() => {
           resolve(2);
       }, 1000);
   }),
   new Promise((resolve, reject) => {
       resolve(3);
       //reject('出错了')
   })
]).then(
   value => console.log(value),
   e => console.log(e)
);

你可能感兴趣的:(Promise详解和手写Promise)