进来看看ES6 Promise最全手写实现

写在开头

  • 这几天看到有些技术群在发Promise相关的一些实现,本身最近也在看ES6的一些内容,因而打算本身也整理一下,提高一下理解;
  • 本文适合一些了解并使用过Promise的人,若是你没有了解或使用过Promise,建议先看一下 阮一峰 ECMAScript6 入门 之Promise

什么是Promise

  • 异步编程的一种解决方案;
  • Promise是一个容器,里面保存着某个将来才会结束的事件(一般是一个异步操做)的结果;

特色

  • 对象的状态不受外界影响。Promise对象表明一个异步操做,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。
  • 一旦状态改变,就不会再变,任什么时候候均可以获得这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected

简单实现

流程分析

  • 图片来源 MDN

初始化一个Promise

  • 原始的Promise
// Promise构造函数接收一个executor函数,executor函数执行完同步或异步操做后,调用它的两个参数resolve和reject
const promise = new Promise(function(resolve, reject) {
  /*
    若是操做成功,调用resolve并传入value
    若是操做失败,调用reject并传入reason
  */
})
复制代码
  • 包含当前的状态
  • 当前的值
  • fulfilled的回调函数数组
  • rejected的回调函数数组
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

const NewPromise = function(executor) {
  const _this = this;
  _this.status = PENDING; // 状态
  _this.data = undefined; // 值
  _this.onResolvedCallback = []; // fulfilled的回调函数数组
  _this.onRejectedCallback = []; // rejected的回调函数数组
  // 成功
  function resolve(value) { ... }
  // 失败
  function reject(reason) { ... }
  try {
    executor(resolve, reject);
  } catch (error) {
    reject(error);
  }
}  
复制代码

完善resolereject

  • resole是成功的调用,须要不状态修改成fulfilled,而后当前的值设为传入的值,遍历执行onResolvedCallback中的回调。
// 成功
function resolve(value) {
    只有pending状态才能转换为fulfilled / rejected
    setTimeout(function() { // 异步执行全部的回调函数
        if (_this.status === PENDING) {
            _this.status = FULFILLED;
            _this.data = value;
            _this.onResolvedCallback.forEach(callback => callback(value));
        }
    });
}
复制代码
  • reject的实现和resolve相似,只是状态修改成rejected及执行onRejectedCallback
// 失败
function reject(reason) {
    setTimeout(function() { // 异步执行全部的回调函数
        if (_this.status === PENDING) {
            _this.status = REJECTED;
            _this.data = reason;
            _this.onRejectedCallback.forEach(callback => callback(reason));
        }
    });
}
复制代码
  • 如今已经实现了基本的Promise,你能够像使用Promise同样使用它,但尚未添加其余的方法。
// 测试
const promise = new NewPromise(function(resolve, reject) {
  console.log('ss', 11)
})
复制代码

then方法

  • Promise对象有一个then方法,用来注册在这个Promise状态肯定后的回调,then方法须要写在原型链上(为何要写在原型上不清楚的可能须要补一下JavaScript基础了)。在Promise/A标准中,明确规定了then要返回一个新的对象,因此在咱们的实现中也返回一个新对象。
// then挂载到原型上
NewPromise.prototype.then = function(onResolved, onRejected) {
  const _this = this;
  if ( typeof onResolved !== 'function') {
   onResolved = function(value) { return value }
  }
  if ( typeof onRejected !== 'function') {
    onRejected = function(reason) { throw reason }
  }

  // 公共判断
  const common = function (data, resolve, reject) {
    // 考虑到有可能throw,咱们将其包在try/catch块里
    try {
      let value = _this.status === FULFILLED
        ? onResolved(data)
        : onRejected(data)
      if( value instanceof Promise) {
        value.then(resolve, reject)
      }
      resolve(value)
    } catch (error) {
      reject(error)
    }
  }
  // 公共判断
  const pendingCommon = function (data, flag, resolve, reject) {
    // 考虑到有可能throw,咱们将其包在try/catch块里
    try {
      let value = flag === FULFILLED
        ? onResolved(data)
        : onRejected(data)
      if( value instanceof Promise) {
        value.then(resolve, reject)
      }
      resolve(value)
    } catch (error) {
      reject(error)
    }
  }

  if (_this.status === PENDING) {
    return new NewPromise(function(resolve, reject) {
      _this.onResolvedCallback.push((value) => {
        pendingCommon(value, FULFILLED, resolve, reject);
      })

      _this.onRejectedCallback.push((reason) => {
        pendingCommon(reason, REJECTED, resolve, reject);
      })
    })
  } else { // resolve / reject
    return new NewPromise(function (resolve, reject) {
      setTimeout(function () {
        common(_this.data, resolve, reject)
      })
    })
  }
}
复制代码

resolve方法再次完善

  • 判断rosolve的值是不是Promise,若是是Promise继续执行.then方法。
// 成功
function resolve(value) { 
    // value 若是是Promise继续执行.then
+   if (value instanceof Promise) {
+     return value.then(resolve, reject)
+   }
    ...
}
复制代码

catch方法

  • 捕获Promise的异常错误。
// catch方法
NewPromise.prototype.catch = function(onRejected) {
  return this.then(null, onRejected)
}
复制代码

finally方法

  • finally()方法用于指定无论Promise对象最后状态如何,都会执行的操做。
// finally
NewPromise.prototype.finally = function (fun) {
  return this.then((value) => {
      // f(); return value;
      // Promise.resolve会等f()的函数执行完再返回结果
      return NewPromise.resolve(fun()).then(() => value);
  }, (err) => {
      return NewPromise.resolve(fun()).then(() => {
          throw err;
      });
  });
};
复制代码

resolve方法

  • 现有对象转为Promise对象,实例的状态为fulfilled
NewPromise.resolve = function(value) {
  if (value instanceof Promise) return value;
    if (value === null) return null;
    // 判断若是是promise
    if (typeof value === 'object' || typeof value === 'function') {
        try {
            // 判断是否有then方法
            let then = value.then;
            if (typeof then === 'function') {
                return new NewPromise(then.call(value)); // 执行value方法
            }
        } catch (e) {
            return new NewPromise( (resolve, reject) =>{
                reject(e);
            });
        }
    }
    return new NewPromise( (resolve, reject) =>{
      resolve(value);
  });
}
复制代码

reject方法

  • 现有对象转为Promise对象,实例的状态为rejected。实现和resolve方法相似,最后return改成reject
NewPromise.reject = function(reason) {
    ...
    return new NewPromise( (resolve, reject) =>{
      reject(reason);
  });
}
复制代码

all方法

  • Promise.all方法用于将多个 Promise 实例,包装成一个新的Promise 实例;方法的参数能够不是数组,但必须具备Iterator接口,且返回的每一个成员都是Promise实例。
// all
NewPromise.all = function(promises) {
  return new NewPromise(function(resolve, reject) {
    const result = []
    // 判断参数属否是数组
    promises = Array.isArray(promises) ? promises : []
    const len = promises.length - 1;
    promises.forEach((promise, index) => {
      promise.then(value => {
        result.push(value)
        if(index === len) {
          resolve(result)
        }
      }, reject)
    })
  }) 
}
复制代码

race方法

  • Promise.race()方法一样是将多个Promise实例,包装成一个新的Promise实例。
  • 只要参数之中有一个实例率先改变状态,Promise.race()的状态就跟着改变。那个率先改变的Promise实例的返回值,就传递给Promise.race()的回调函数。
// race
NewPromise.race = function (promises) {
  return new NewPromise((resolve, reject) => {
    promises = Array.isArray(promises) ? promises : []
    promises.forEach(promise => {
      promise.then(resolve, reject)
    })
  })
}
复制代码

deferred方法

  • 返回一个有promise方法的对象。
// defered
NewPromise.deferred = function() {
  const dfd = {}
  dfd.promise = new NewPromise(function(resolve, reject) {
    dfd.resolve = resolve
    dfd.reject = reject
  })
  return dfd
}
复制代码

allSettled方法

  • Promise.allSettled()方法接受一组Promise实例做为参数,包装成一个新的Promise实例,只有等到全部这些参数实例都返回结果,无论是fulfilled仍是rejected,包装实例才会结束。返回一个包含全部结果的数组。
NewPromise.allSettled = function (promises) {
  return new NewPromise((resolve, reject) => {
    promises = Array.isArray(promises) ? promises : []
    let len = promises.length;
    const argslen = len;
    if (len === 0) return resolve([]);
    let args = Array.prototype.slice.call(promises);
    function resolvePromise(index, value) {
      if(typeof value === 'object') { // 传入的是不是object
        const then = value.then;
        if(typeof then === 'function'){
          then.call(value, function(val) {
            args[index] = { status: 'fulfilled', value: val};
            if(--len === 0) {
              resolve(args);
            }
          }, function(e) {
            args[index] = { status: 'rejected', reason: e };
            if(--len === 0) {
              reject(args);
            }
          })
        }
      }
    }
 
    for(let i = 0; i < argslen; i++){
      resolvePromise(i, args[i]);
    }
  })
}
复制代码

测试

基础测试

// 测试
const promise = new NewPromise(function(resolve, reject) {
  console.log('ss', 11);
  resolve(123);
})
复制代码

then测试

promise.then(val => {
  console.log('val', val)
})
复制代码

catch测试

const promise = new NewPromise(function(resolve, reject) {
  console.log('ss', 11);
  reject('errr')
})
promise.catch(err => {
  console.log('err', err)
})
复制代码

finally测试

const resolved = NewPromise.resolve(1);
const rejected = NewPromise.reject(-1);
const resolved1 = NewPromise.resolve(17);

const p = NewPromise.all([resolved, resolved1, rejected]);
p.then((result) => {
  console.log('result', result)
}).catch(err => {
  console.log('err', err)
}).finally(() => {
  console.log('finally')
})
复制代码

resolve测试

const resolved = NewPromise.resolve(1);
resolved.then(val => {
    console.log('resolved', val)
})
复制代码

reject测试

const rejected = NewPromise.reject(-1);
rejected.catch(val => {
  console.log('rejected', val)
})
复制代码

all测试

const resolved = NewPromise.resolve(1);
const rejected = NewPromise.reject(-1);
const resolved1 = NewPromise.resolve(17);

const p = NewPromise.all([resolved, resolved1, rejected]);
p.then((result) => {
  console.log('result', result)
}).catch(err => {
  console.log('err', err)
})
复制代码

allSettled测试

const resolved = NewPromise.resolve(1);
const rejected = NewPromise.reject(-1);
const resolved1 = NewPromise.resolve(17);

const p = NewPromise.allSettled([resolved, resolved1, rejected]);
p.then((result) => {
  console.log('result', result)
})
复制代码

所有代码

/*
 * @Author: detanx 
 * @Date: 2020-05-11 17:39:52 
 * @Last Modified by:   detanx 
 * @Last Modified time: 2020-05-11 17:39:52 
 */
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

const NewPromise = function(executor) {
  const _this = this;
  _this.status = PENDING;
  _this.data = undefined;
  _this.onResolvedCallback = [];
  _this.onRejectedCallback = [];

  // 成功
  function resolve(value) {
    if (value instanceof Promise) {
      return value.then(resolve, reject)
    }
    setTimeout(function() { // 异步执行全部的回调函数
      if (_this.status === PENDING) {
        _this.status = FULFILLED;
        _this.data = value;
        _this.onResolvedCallback.forEach(callback => callback(value));
      }
    })
  }
  // 失败
  function reject(reason) {
    setTimeout(function() { // 异步执行全部的回调函数
      if (_this.status === PENDING) {
        _this.status = REJECTED;
        _this.data = reason;
        _this.onRejectedCallback.forEach(callback => callback(reason));
      }
    })
  }

  try {
    executor(resolve, reject);
  } catch (error) {
    reject(error);
  }
}  
// then
NewPromise.prototype.then = function(onResolved, onRejected) {
  const _this = this;
  if ( typeof onResolved !== 'function') {
   onResolved = function(value) { return value }
  }
  if ( typeof onRejected !== 'function') {
    onRejected = function(reason) { throw reason }
  }

  // 公共判断
  const common = function (data, resolve, reject) {
    // 考虑到有可能throw,咱们将其包在try/catch块里
    try {
      let value = _this.status === FULFILLED
        ? onResolved(data)
        : onRejected(data)
      if( value instanceof Promise) {
        value.then(resolve, reject)
      }
      resolve(value)
    } catch (error) {
      reject(error)
    }
  }
  // 公共判断
  const pendingCommon = function (data, flag, resolve, reject) {
    // 考虑到有可能throw,咱们将其包在try/catch块里
    try {
      let value = flag === FULFILLED
        ? onResolved(data)
        : onRejected(data)
      if( value instanceof Promise) {
        value.then(resolve, reject)
      }
      resolve(value)
    } catch (error) {
      reject(error)
    }
  }

  if (_this.status === PENDING) {
    return new NewPromise(function(resolve, reject) {
      _this.onResolvedCallback.push((value) => {
        pendingCommon(value, FULFILLED, resolve, reject);
      })

      _this.onRejectedCallback.push((reason) => {
        pendingCommon(reason, REJECTED, resolve, reject);
      })
    })
  } else { // resolve / reject
    return new NewPromise(function (resolve, reject) {
      setTimeout(function () {
        common(_this.data, resolve, reject)
      })
    })
  }
}
NewPromise.resolve = function(value) {
  if (value instanceof Promise) return value;
    if (value === null) return null;
    // 判断若是是promise
    if (typeof value === 'object' || typeof value === 'function') {
        try {
            // 判断是否有then方法
            let then = value.then;
            if (typeof then === 'function') {
                return new NewPromise(then.call(value)); // 执行value方法
            }
        } catch (e) {
            return new NewPromise( (resolve, reject) =>{
                reject(e);
            });
        }
    }
    return new NewPromise( (resolve, reject) =>{
      resolve(value);
  });
}
NewPromise.reject = function(value) {
  if (value instanceof Promise) return value;
    if (value === null) return null;
    // 判断若是是promise
    if (typeof value === 'object' || typeof value === 'function') {
        try {
            // 判断是否有then方法
            let then = value.then;
            if (typeof then === 'function') {
                return new NewPromise(then.call(value)); // 执行value方法
            }
        } catch (e) {
            return new NewPromise( (resolve, reject) =>{
                reject(e);
            });
        }
    }
    return new NewPromise( (resolve, reject) =>{
      reject(value);
  });
}
// catch方法
NewPromise.prototype.catch = function(onRejected) {
  return this.then(null, onRejected)
}
// defered
NewPromise.deferred = function() {
  const dfd = {}
  dfd.promise = new NewPromise(function(resolve, reject) {
    dfd.resolve = resolve
    dfd.reject = reject
  })
  return dfd
}
// all
NewPromise.all = function(promises) {
  return new NewPromise(function(resolve, reject) {
    const result = []
    promises = Array.isArray(promises) ? promises : []
    const len = promises.length - 1;
    promises.forEach((promise, index) => {
      promise.then(value => {
        result.push(value)
        if(index === len) {
          resolve(result)
        }
      }, reject)
    })
  }) 
}
// race
NewPromise.race = function (promises) {
  return new NewPromise((resolve, reject) => {
    promises = Array.isArray(promises) ? promises : []
    promises.forEach(promise => {
      promise.then(resolve, reject)
    })
  })
}
// allSettled
NewPromise.allSettled = function (promises) {
  return new NewPromise((resolve, reject) => {
    promises = Array.isArray(promises) ? promises : []
    let len = promises.length;
    const argslen = len;
    if (len === 0) return resolve([]);
    let args = Array.prototype.slice.call(promises);
    function resolvePromise(index, value) {
      if(typeof value === 'object') {
        const then = value.then;
        if(typeof then === 'function'){
          then.call(value, function(val) {
            args[index] = { status: 'fulfilled', value: val};
            if(--len === 0) {
              resolve(args);
            }
          }, function(e) {
            args[index] = { status: 'rejected', reason: e };
            if(--len === 0) {
              reject(args);
            }
          })
        }
      }
    }
 
    for(let i = 0; i < argslen; i++){
      resolvePromise(i, args[i]);
    }
  })
}

// 测试
// const promise = new NewPromise(function(resolve, reject) {
//   console.log('ss', 11)
//   // resolve(123)
//   reject('errr')
//   // throw 'ree'
// })
// promise.catch(val => {
//   console.log('val', val)
// })
// const promise1 = new NewPromise(function(resolve, reject) {
//   console.log('ss', 11)
//   resolve(123)
//   // reject('errr')
// })
// const rejected = NewPromise.reject(-1);
// rejected.catch(val => {
//     console.log('rejected', val)
//   })
// console.log('resolved', resolved)
const resolved = NewPromise.resolve(1);
const rejected = NewPromise.reject(-1);
const resolved1 = NewPromise.resolve(17);

const p = NewPromise.all([resolved, resolved1, rejected]);
p.then((result) => {
  console.log('result', result)
}).catch(err => {
  console.log('err', err)
})
复制代码

参考

阮一峰 ECMAScript 6 入门
22 道高频 JavaScript 手写面试题及答案es6

  • 有帮到您的话留下你的赞👍呗,你的支持就是我产出的动力。
相关文章
相关标签/搜索