promise的实现

Posted oxspirt

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了promise的实现相关的知识,希望对你有一定的参考价值。

原文:https://blog.csdn.net/sinat_17775997/article/details/70170939

----------------------------------------

本文缘起前段时间一朋友换工作时,笔试题中要求手写一个Promise。在工作中虽已大量使用Promise,其原理却没有深入探究过,换做自己,当场也很难手写一个完善的Promise实现。近期补了一些课,以本文来彻底的理解Promise实现原理。

http://www.jianshu.com/p/f8b052c71550

1.Promise是什么

Promise是抽象异步处理对象以及对其进行各种操作的组件,可以将复杂的异步处理轻松的进行模式化。
使用Promise进行异步处理的一个例子

  1.  
    functiongetUserId() {
  2.  
    return new Promise(function (resolve, reject) {
  3.  
    // 异步请求
  4.  
    Y.io(‘/userid/1‘, {
  5.  
    on: {
  6.  
    success: function (id, res) {
  7.  
    var o = JSON.parse(res);
  8.  
    if (o.status === 1) {
  9.  
    resolve(o.id);
  10.  
    } else {
  11.  
    // 请求失败,返回错误信息
  12.  
    reject(o.errorMsg);
  13.  
    }
  14.  
    }
  15.  
    }
  16.  
    });
  17.  
    });
  18.  
    }
  19.  
     
  20.  
    getUserId().then(function (id) {
  21.  
    // do sth with id
  22.  
    }, function (error) {
  23.  
    console.log(error);
  24.  
    });

如对Promise的使用尚不了解,推荐阅读JavaScript Promise Cookbook中文版

---------------------

https://github.com/bruce-xu/Promise/blob/master/Promise.js

/**
 * @file JS Promise实现
 * @author bruxexyj@gmail.com
 */
(function (factory, global) {
    if (typeof define === ‘function‘ && define.amd) {
        define(factory);
    }
    else if (typeof module === ‘object‘ && module.exports) {
        module.exports = exports = factory();
    }
    else {
        global.Promise = factory();
    }
}(function () {

    /**
     * Promise对象的内部状态
     *
     * @type {Object}
     */
    var Status = {
        PENDING: ‘pending‘,
        FULLFILLED: ‘resolved‘,
        REJECTED: ‘rejected‘
    };

    function empty() {}

    /**
     * Promise构造函数
     *
     * @constructor
     * @param {Function} resolver 此Promise对象管理的任务
     */
    function Promise(resolver) {
        // ES6原生的Promise构造函数中,若不通过`new`调用Promise的构造函数,会抛出TypeError异常。此处与其一致
        if (!(this instanceof Promise)) {
            throw new TypeError(‘TypeError: undefined is not a promise‘);
        }

        // ES6原生的Promise构造函数中,若无作为函数的resolver参数,会抛出TypeError异常。此处与其一致
        if (typeof resolver !== ‘function‘) {
            throw new TypeError(‘TypeError: Promise resolver undefined is not a function‘);
        }

        /**
         * Promise对象内部的状态,初始为`pending`。状态只能由`pending`到`fullfilled`或`rejected`
         *
         * @type {string}
         */
        this._status = Status.PENDING;

        /**
         * Promise对象resolved/rejected后拥有的data/reason
         *
         *  - 此处保存此值是为了当一个Promise对象被resolved或rejected后,继续对其调用`then`添加任务,后续处理仍能获得当前Promise的值
         *
         * @type {Mixed}
         */
        this._value;

        /**
         * 当前Promise被resolved/rejected后,需处理的任务
         *
         *  - 由于同一个Promise对象可以调用多次`then`方法,以添加多个并行任务,所以此处是一个数组
         *
         * @type {Array.<Function>}
         */
        this._doneCallbacks = [];
        this._failCallbacks = [];

        var promise = this;
        resolver(
            function (data) {
                resolve(promise, data);
            },
            function (reason) {
                reject(promise, reason);
            }
        );
    }

    Promise.prototype = {

        constructor: Promise,

        /**
         * Promise的`then`方法
         *
         * @param {Function|Mixed} onResolve 当前Promise对象被resolved后,需处理的任务
         * @param {Function|Mixed} onReject 当前Promise对象被rejected后,需处理的任务
         * @return {Promise} 返回一个新的Promise对象,用于链式操作
         */
        then: function (onResolve, onReject) {
            var promise = new Promise(empty);

            this._doneCallbacks.push(makeCallback(promise, onResolve, ‘resolve‘));
            this._failCallbacks.push(makeCallback(promise, onReject, ‘reject‘));

            // 如果在一个已经被fullfilled或rejected的promise上调用then,则需要直接执行通过then注册的回调函数
            run(this);

            return promise;
        },

        /**
         * Promise的`done`方法
         *
         * @param {Function|Mixed} onResolve 当前Promise对象被resolved后,需处理的任务
         * @return {Promise} 返回一个新的Promise对象,用于链式操作
         */
        done: function (onResolve) {
            return this.then(onResolve, null);
        },

        /**
         * Promise的`fail`方法
         *
         * @param {Function|Mixed} onReject 当前Promise对象被rejected后,需处理的任务
         * @return {Promise} 返回一个新的Promise对象,用于链式操作
         */
        fail: function (onReject) {
            return this.then(null, onReject);
        },

        /**
         * Promise的`catch`方法
         *
         * @param {Function|Mixed} onFail 当前Promise对象被rejected后,需处理的任务
         * @return {Promise} 返回一个新的Promise对象,用于链式操作
         */
        catch: function (onFail) {
            return this.then(null, onFail);
        }
    };

    /**
     * 创建一个Promise对象,并用给定值resolve它
     *
     * @param {Mixed} value 用于resolve新创建的Promise对象的值
     * @return {Promise} 返回一个新的Promise对象,用于链式操作
     */
    Promise.resolve = function (value) {
        var promise = new Promise(empty);
        resolve(promise, value);
        return promise;
    };

    /**
     * 创建一个Promise对象,并用给定值reject它
     *
     * @param {Mixed} reason 用于reject新创建的Promise对象的值
     * @return {Promise} 返回一个新的Promise对象,用于链式操作
     */
    Promise.reject = function (reason) {
        var promise = new Promise(empty);
        reject(promise, reason);
        return promise;
    };

    /**
     * 返回一个promise,这个promise在iterable中的任意一个promise被解决或拒绝后,
     * 立刻以相同的解决值被解决或以相同的拒绝原因被拒绝
     *
     * @param {Iterable.<Promise|Mixed>} iterable 一组Promise对象或其它值
     * @return {Promise} 返回一个新的Promise对象,用于链式操作
     */
    Promise.race = function (iterable) {
        if (!iterable || !iterable.hasOwnProperty(‘length‘)) {
            throw new TypeError(‘TypeError: Parameter `iterable` must be a iterable object‘);
        }

        var promise = new Promise(empty);
        for (var i = 0, len = iterable.length; i < len; i++) {
            var iterate = iterable[i];
            if (!(iterate instanceof Promise)) {
                iterate = Promise.resolve(iterate);
            }

            iterate.then(resolveRaceCallback, rejectRaceCallback);
        }

        var settled = false;

        function resolveRaceCallback(data) {
            if (settled) {
                return;
            }

            settled = true;
            resolve(promise, data);
        }

        function rejectRaceCallback(reason) {
            if (settled) {
                return;
            }

            settled = true;
            reject(promise, reason);
        }
    };

    /**
     * 返回一个promise,该promise会在iterable参数内的所有promise都被解决后被解决
     *
     * @param {Iterable.<Promise|Mixed>} iterable 一组Promise对象或其它值
     * @return {Promise} 返回一个新的Promise对象,用于链式操作
     */
    Promise.all = function (iterable) {
        if (!iterable || !iterable.hasOwnProperty(‘length‘)) {
            throw new TypeError(‘TypeError: Parameter `iterable` must be a iterable object‘);
        }

        var promise = new Promise(empty);
        var length = iterable.length;
        for (var i = 0; i < length; i++) {
            var iterate = iterable[i];
            if (!(iterate instanceof Promise)) {
                iterate = Promise.resolve(iterate);
            }

            iterate.then(makeAllCallback(iterate, i, ‘resolve‘), makeAllCallback(iterate, i, ‘reject‘));
        }

        var result = [];
        var count = 0;

        function makeAllCallback(iterate, index, action) {
            return function (value) {
                if (action === ‘reject‘) {
                    reject(promise, value);
                    return;
                }

                result[index] = value;

                if (++count === length) {
                    resolve(promise, result);
                }
            }
        }
    };

    /**
     * 返回一个Deferred对象,包含一个新创建的Promise对象,以及`resolve`和`reject`方法
     *
     * @return {Deferred}
     */
    Promise.defer = function () {
        var promise = new Promise(empty);

        return {
            promise: promise,
            resolve: function (data) {
                resolve(promise, data);
            },
            reject: function (reason) {
                reject(promise, reason);
            }
        };
    };

    function run(promise) {
        // `then`方法中也会调用,所以此处仍需做一次判断
        if (promise._status === Status.PENDING) {
            return;
        }

        var value = promise._value;
        var callbacks = promise._status === Status.FULLFILLED
            ? promise._doneCallbacks
            : promise._failCallbacks;

        // Promise需要异步操作
        setTimeout(function () {
            for (var i = 0, len = callbacks.length; i < len; i++) {
                callbacks[i](value);
            }
        });

        // 每个promise只能被执行一次。虽然`_doneCallbacks`和`_failCallbacks`用户不应该直接访问,
        // 但还是可以访问到,保险起见,做清空处理。
        promise._doneCallbacks = [];
        promise._failCallbacks = [];
    }

    function resolve(promise, data) {
        if (promise._status !== Status.PENDING) {
            return;
        }

        promise._status = Status.FULLFILLED;
        promise._value = data;

        run(promise);
    }

    function reject(promise, reason) {
        if (promise._status !== Status.PENDING) {
            return;
        }

        promise._status = Status.REJECTED;
        promise._value = reason;

        run(promise);
    }

    function makeCallback(promise, callback, action) {
        return function promiseCallback(value) {
            // 如果传递了callback,则使用前一个promise传递过来的值作为参数调用callback,
            // 并根据callback的调用结果来处理当前promise
            if (typeof callback === ‘function‘) {
                var x;
                try {
                    x = callback(value);
                }
                catch (e) {
                    // 如果调用callback时抛出异常,则直接用此异常对象reject当前promise
                    reject(promise, e);
                }

                // 如果callback的返回值是当前promise,为避免造成死循环,需要抛出异常
                // 根据Promise+规范,此处应抛出TypeError异常
                if (x === promise) {
                    var reason = new TypeError(‘TypeError: The return value could not be same with the promise‘);
                    reject(promise, reason);
                }
                // 如果返回值是一个Promise对象,则当返回的Promise对象被resolve/reject后,再resolve/reject当前Promise
                else if (x instanceof Promise) {
                    x.then(
                        function (data) {
                            resolve(promise, data);
                        },
                        function (reason) {
                            reject(promise, reason);
                        }
                    );
                }
                else {
                    var then;
                    (function resolveThenable(x) {
                        // 如果返回的是一个Thenable对象(此处逻辑有点坑,参照Promise+的规范实现)
                        if (x && (typeof x === ‘object‘|| typeof x === ‘function‘)) {
                            try {
                                then = x.then;
                            }
                            catch (e) {
                                reject(promise, e);
                                return;
                            }

                            if (typeof then === ‘function‘) {
                                // 调用Thenable对象的`then`方法时,传递进去的`resolvePromise`和`rejectPromise`方法(及下面的两个匿名方法)
                                // 可能会被重复调用。但Promise+规范规定这两个方法有且只能有其中的一个被调用一次,多次调用将被忽略。
                                // 此处通过`invoked`来处理重复调用
                                var invoked = false;
                                try {
                                    then.call(
                                        x,
                                        function (y) {
                                            if (invoked) {
                                                return;
                                            }
                                            invoked = true;

                                            // 避免死循环
                                            if (y === x) {
                                                throw new TypeError(‘TypeError: The return value could not be same with the previous thenable object‘);
                                            }

                                            // y仍有可能是thenable对象,递归调用
                                            resolveThenable(y);
                                        },
                                        function (e) {
                                            if (invoked) {
                                                return;
                                            }
                                            invoked = true;

                                            reject(promise, e);
                                        }
                                    );
                                }
                                catch (e) {
                                    // 如果`resolvePromise`和`rejectPromise`方法被调用后,再抛出异常,则忽略异常
                                    // 否则用异常对象reject此Promise对象
                                    if (!invoked) {
                                        reject(promise, e);
                                    }
                                }
                            }
                            else {
                                resolve(promise, x);
                            }
                        }
                        else {
                            resolve(promise, x);
                        }
                    }(x));
                }
            }
            // 如果未传递callback,直接用前一个promise传递过来的值resolve/reject当前Promise对象
            else {
                action === ‘resolve‘
                    ? resolve(promise, value)
                    : reject(promise, value);
            }
        };
    }

    return Promise;
}, this));

  

/**
  * @file JS Promise实现
  * @author bruxexyj@gmail.com
  */
  (function (factory, global) {
  if (typeof define === ‘function‘ && define.amd) {
  define(factory);
  }
  else if (typeof module === ‘object‘ && module.exports) {
  module.exports = exports = factory();
  }
  else {
  global.Promise = factory();
  }
  }(function () {
   
  /**
  * Promise对象的内部状态
  *
  * @type {Object}
  */
  var Status = {
  PENDING: ‘pending‘,
  FULLFILLED: ‘resolved‘,
  REJECTED: ‘rejected‘
  };
   
  function empty() {}
   
  /**
  * Promise构造函数
  *
  * @constructor
  * @param {Function} resolver 此Promise对象管理的任务
  */
  function Promise(resolver) {
  // ES6原生的Promise构造函数中,若不通过`new`调用Promise的构造函数,会抛出TypeError异常。此处与其一致
  if (!(this instanceof Promise)) {
  throw new TypeError(‘TypeError: undefined is not a promise‘);
  }
   
  // ES6原生的Promise构造函数中,若无作为函数的resolver参数,会抛出TypeError异常。此处与其一致
  if (typeof resolver !== ‘function‘) {
  throw new TypeError(‘TypeError: Promise resolver undefined is not a function‘);
  }
   
  /**
  * Promise对象内部的状态,初始为`pending`。状态只能由`pending`到`fullfilled`或`rejected`
  *
  * @type {string}
  */
  this._status = Status.PENDING;
   
  /**
  * Promise对象resolved/rejected后拥有的data/reason
  *
  * - 此处保存此值是为了当一个Promise对象被resolved或rejected后,继续对其调用`then`添加任务,后续处理仍能获得当前Promise的值
  *
  * @type {Mixed}
  */
  this._value;
   
  /**
  * 当前Promise被resolved/rejected后,需处理的任务
  *
  * - 由于同一个Promise对象可以调用多次`then`方法,以添加多个并行任务,所以此处是一个数组
  *
  * @type {Array.<Function>}
  */
  this._doneCallbacks = [];
  this._failCallbacks = [];
   
  var promise = this;
  resolver(
  function (data) {
  resolve(promise, data);
  },
  function (reason) {
  reject(promise, reason);
  }
  );
  }
   
  Promise.prototype = {
   
  constructor: Promise,
   
  /**
  * Promise的`then`方法
  *
  * @param {Function|Mixed} onResolve 当前Promise对象被resolved后,需处理的任务
  * @param {Function|Mixed} onReject 当前Promise对象被rejected后,需处理的任务
  * @return {Promise} 返回一个新的Promise对象,用于链式操作
  */
  then: function (onResolve, onReject) {
  var promise = new Promise(empty);
   
  this._doneCallbacks.push(makeCallback(promise, onResolve, ‘resolve‘));
  this._failCallbacks.push(makeCallback(promise, onReject, ‘reject‘));
   
  // 如果在一个已经被fullfilled或rejected的promise上调用then,则需要直接执行通过then注册的回调函数
  run(this);
   
  return promise;
  },
   
  /**
  * Promise的`done`方法
  *
  * @param {Function|Mixed} onResolve 当前Promise对象被resolved后,需处理的任务
  * @return {Promise} 返回一个新的Promise对象,用于链式操作
  */
  done: function (onResolve) {
  return this.then(onResolve, null);
  },
   
  /**
  * Promise的`fail`方法
  *
  * @param {Function|Mixed} onReject 当前Promise对象被rejected后,需处理的任务
  * @return {Promise} 返回一个新的Promise对象,用于链式操作
  */
  fail: function (onReject) {
  return this.then(null, onReject);
  },
   
  /**
  * Promise的`catch`方法
  *
  * @param {Function|Mixed} onFail 当前Promise对象被rejected后,需处理的任务
  * @return {Promise} 返回一个新的Promise对象,用于链式操作
  */
  catch: function (onFail) {
  return this.then(null, onFail);
  }
  };
   
  /**
  * 创建一个Promise对象,并用给定值resolve它
  *
  * @param {Mixed} value 用于resolve新创建的Promise对象的值
  * @return {Promise} 返回一个新的Promise对象,用于链式操作
  */
  Promise.resolve = function (value) {
  var promise = new Promise(empty);
  resolve(promise, value);
  return promise;
  };
   
  /**
  * 创建一个Promise对象,并用给定值reject它
  *
  * @param {Mixed} reason 用于reject新创建的Promise对象的值
  * @return {Promise} 返回一个新的Promise对象,用于链式操作
  */
  Promise.reject = function (reason) {
  var promise = new Promise(empty);
  reject(promise, reason);
  return promise;
  };
   
  /**
  * 返回一个promise,这个promise在iterable中的任意一个promise被解决或拒绝后,
  * 立刻以相同的解决值被解决或以相同的拒绝原因被拒绝
  *
  * @param {Iterable.<Promise|Mixed>} iterable 一组Promise对象或其它值
  * @return {Promise} 返回一个新的Promise对象,用于链式操作
  */
  Promise.race = function (iterable) {
  if (!iterable || !iterable.hasOwnProperty(‘length‘)) {
  throw new TypeError(‘TypeError: Parameter `iterable` must be a iterable object‘);
  }
   
  var promise = new Promise(empty);
  for (var i = 0, len = iterable.length; i < len; i++) {
  var iterate = iterable[i];
  if (!(iterate instanceof Promise)) {
  iterate = Promise.resolve(iterate);
  }
   
  iterate.then(resolveRaceCallback, rejectRaceCallback);
  }
   
  var settled = false;
   
  function resolveRaceCallback(data) {
  if (settled) {
  return;
  }
   
  settled = true;
  resolve(promise, data);
  }
   
  function rejectRaceCallback(reason) {
  if (settled) {
  return;
  }
   
  settled = true;
  reject(promise, reason);
  }
  };
   
  /**
  * 返回一个promise,该promise会在iterable参数内的所有promise都被解决后被解决
  *
  * @param {Iterable.<Promise|Mixed>} iterable 一组Promise对象或其它值
  * @return {Promise} 返回一个新的Promise对象,用于链式操作
  */
  Promise.all = function (iterable) {
  if (!iterable || !iterable.hasOwnProperty(‘length‘)) {
  throw new TypeError(‘TypeError: Parameter `iterable` must be a iterable object‘);
  }
   
  var promise = new Promise(empty);
  var length = iterable.length;
  for (var i = 0; i < length; i++) {
  var iterate = iterable[i];
  if (!(iterate instanceof Promise)) {
  iterate = Promise.resolve(iterate);
  }
   
  iterate.then(makeAllCallback(iterate, i, ‘resolve‘), makeAllCallback(iterate, i, ‘reject‘));
  }
   
  var result = [];
  var count = 0;
   
  function makeAllCallback(iterate, index, action) {
  return function (value) {
  if (action === ‘reject‘) {
  reject(promise, value);
  return;
  }
   
  result[index] = value;
   
  if (++count === length) {
  resolve(promise, result);
  }
  }
  }
  };
   
  /**
  * 返回一个Deferred对象,包含一个新创建的Promise对象,以及`resolve`和`reject`方法
  *
  * @return {Deferred}
  */
  Promise.defer = function () {
  var promise = new Promise(empty);
   
  return {
  promise: promise,
  resolve: function (data) {
  resolve(promise, data);
  },
  reject: function (reason) {
  reject(promise, reason);
  }
  };
  };
   
  function run(promise) {
  // `then`方法中也会调用,所以此处仍需做一次判断
  if (promise._status === Status.PENDING) {
  return;
  }
   
  var value = promise._value;
  var callbacks = promise._status === Status.FULLFILLED
  ? promise._doneCallbacks
  : promise._failCallbacks;
   
  // Promise需要异步操作
  setTimeout(function () {
  for (var i = 0, len = callbacks.length; i < len; i++) {
  callbacks[i](value);
  }
  });
   
  // 每个promise只能被执行一次。虽然`_doneCallbacks`和`_failCallbacks`用户不应该直接访问,
  // 但还是可以访问到,保险起见,做清空处理。
  promise._doneCallbacks = [];
  promise._failCallbacks = [];
  }
   
  function resolve(promise, data) {
  if (promise._status !== Status.PENDING) {
  return;
  }
   
  promise._status = Status.FULLFILLED;
  promise._value = data;
   
  run(promise);
  }
   
  function reject(promise, reason) {
  if (promise._status !== Status.PENDING) {
  return;
  }
   
  promise._status = Status.REJECTED;
  promise._value = reason;
   
  run(promise);
  }
   
  function makeCallback(promise, callback, action) {
  return function promiseCallback(value) {
  // 如果传递了callback,则使用前一个promise传递过来的值作为参数调用callback,
  // 并根据callback的调用结果来处理当前promise
  if (typeof callback === ‘function‘) {
  var x;
  try {
  x = callback(value);
  }
  catch (e) {
  // 如果调用callback时抛出异常,则直接用此异常对象reject当前promise
  reject(promise, e);
  }
   
  // 如果callback的返回值是当前promise,为避免造成死循环,需要抛出异常
  // 根据Promise+规范,此处应抛出TypeError异常
  if (x === promise) {
  var reason = new TypeError(‘TypeError: The return value could not be same with the promise‘);
  reject(promise, reason);
  }
  // 如果返回值是一个Promise对象,则当返回的Promise对象被resolve/reject后,再resolve/reject当前Promise
  else if (x instanceof Promise) {
  x.then(
  function (data) {
  resolve(promise, data);
  },
  function (reason) {
  reject(promise, reason);
  }
  );
  }
  else {
  var then;
  (function resolveThenable(x) {
  // 如果返回的是一个Thenable对象(此处逻辑有点坑,参照Promise+的规范实现)
  if (x && (typeof x === ‘object‘|| typeof x === ‘function‘)) {
  try {
  then = x.then;
  }
  catch (e) {
  reject(promise, e);
  return;
  }
   
  if (typeof then === ‘function‘) {
  // 调用Thenable对象的`then`方法时,传递进去的`resolvePromise`和`rejectPromise`方法(及下面的两个匿名方法)
  // 可能会被重复调用。但Promise+规范规定这两个方法有且只能有其中的一个被调用一次,多次调用将被忽略。
  // 此处通过`invoked`来处理重复调用
  var invoked = false;
  try {
  then.call(
  x,
  function (y) {
  if (invoked) {
  return;
  }
  invoked = true;
   
  // 避免死循环
  if (y === x) {
  throw new TypeError(‘TypeError: The return value could not be same with the previous thenable object‘);
  }
   
  // y仍有可能是thenable对象,递归调用
  resolveThenable(y);
  },
  function (e) {
  if (invoked) {
  return;
  }
  invoked = true;
   
  reject(promise, e);
  }
  );
  }
  catch (e) {
  // 如果`resolvePromise`和`rejectPromise`方法被调用后,再抛出异常,则忽略异常
  // 否则用异常对象reject此Promise对象
  if (!invoked) {
  reject(promise, e);
  }
  }
  }
  else {
  resolve(promise, x);
  }
  }
  else {
  resolve(promise, x);
  }
  }(x));
  }
  }
  // 如果未传递callback,直接用前一个promise传递过来的值resolve/reject当前Promise对象
  else {
  action === ‘resolve‘
  ? resolve(promise, value)
  : reject(promise, value);
  }
  };
  }
   
  return Promise;
  }, this));

以上是关于promise的实现的主要内容,如果未能解决你的问题,请参考以下文章

前端面试题之手写promise

澄清 node.js + promises 片段

什么时候然后从Promise.all()的子句运行?

深入 Promise——Promise 实现详解

promise实现原理代码

从源码看 Promise 概念与实现