Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

promise #12

Open
cisen opened this issue Jul 18, 2018 · 1 comment
Open

promise #12

cisen opened this issue Jul 18, 2018 · 1 comment

Comments

@cisen
Copy link
Owner

cisen commented Jul 18, 2018

技术说明

prototype

  1. prototype的函数要实例化才能访问
  2. new方法会先于构建函数的执行,先new完创建好对象,绑定this,然后构建函数就能使用this了
  3. 类内的this是可以通过this.访问prototype原型属性的如this.bb
  4. new的优先级和.(成员访问)的优先级是一样的,具体见:优先级。new aa().bb()由于new在左边所以先执行new。但是无参new的优先级比.(成员访问)底,所以new aa.bb()是优先执行完bb()再new
function aa (){
  this.bb // 这里可以直接访问到bb 
}
aa.prototype.bb = () => {}
aa.bb // undefine
var cc = new aa();
cc.bb // function
// 这句会先执行new aa(),然后会调new出来的对象的bb属性,这个比较神奇
var dd = new aa().bb()

new原理

  1. 所有对象都可以通过__proto__遍历原型访问到它或它的父的属性
  2. new执行将this绑定到一个新的对象并执行构建函数,并将__proto__属性指定到类的prototype,最后返回那个新对象
    实现一个new
function new(F){
    var obj = {'__proto__': F.prototype};  /*第一步*/
    return function() {
        F.apply(obj, arguments);           /*第二步*/
        return obj;                        /*第三步*/
    }
}
// 或者
new Animal("cat") = {
    // 所有对象都继承自基础对象,所以原型链会找到基础对象
    var obj = {};
    obj.__proto__ = Animal.prototype;
    var result = Animal.call(obj,"cat");
    return typeof result === 'object'? result : obj;
}

实现

  1. then的执行会有一次深层递归,先执行完最顶层的then,在执行根的then
  2. promise像一坐闭包山,一层一层的,每一层都是then,层与层的区分考this绑定
  3. 主要有两层局部变量,一个是promise顶层,一个是resolve层。实际上就是执行一个函数,在函数执行的不同阶段修改promise闭包不同的局部变量。
  4. 主要有三步:1. 构建promise函数,2. 执行resolve函数,3. 检查有没有then,有则继续执行
  5. getThen主要是判断是否有深层嵌套promise的情况。因为一般只有在promise()就完成,然后利用new的对象执行then,比如:
// 不会再resovle里面传入一个promise作为参数,如果传入则需要使用getThen判断并深入嵌套
let myFirstPromise = new Promise((resolve, reject) => {
  setTimeout(function(){
    resolve("Success!"); // Yay! Everything went well!
  }, 250);
});
myFirstPromise.then((successMessage) => {
});
  1. 实现then传值的原理是,先执行异步函数得到值,然后判断是否有then有则传值到then继续执行,只是嵌套的情况。promise().then().then()的递归传值原理是,在执行then的时候,this还指向上一个promise,上一个promise有个this.data属性指向上一个promise的结果。然后通过bind,将this绑到下一个promise,并传值下去。
;(function(scope) {
    var PENDING = 'pending';
    var RESOLVED = 'resolved';
    var REJECTED = 'rejected';
    var UNDEFINED = void 0;

    function CallbackItem(promise, onResolved, onRejected) {
        this.promise = promise;
        this.onResolved = typeof onResolved === 'function' ? onResolved : function(v) {
            return v };
        this.onRejected = typeof onRejected === 'function' ? onRejected : function(v) {
            throw v };
    }
    CallbackItem.prototype.resolve = function(value) {
        executeCallbackAsync.bind(this.promise)(this.onResolved, value);
    }
    CallbackItem.prototype.reject = function(value) {
        executeCallbackAsync.bind(this.promise)(this.onRejected, value);
    }
    // 如果有obj有then属性函数,则返回一个then函数,this绑定到obj,接受使用then时的参数
    function getThen(obj) {
        var then = obj && obj.then;
        if (obj && typeof obj === 'object' && typeof then === 'function') {
            return function appyThen() {
                // this绑定到boj并执行then方法
                then.apply(obj, arguments);
            };
        }
    }
    // 如果resolve(res)的res还是一个promise,则先执行完自己的resolve,再继续执行res的then方法,this绑定到res
    // 这里可以将res的所有then方法递归完
    function executeCallback(type, x) {
        var isResolve = type === 'resolve',
            thenable;
        // 如果客户使用resolve(res)时,res是一个函数或者对象,x就是res,则去判断
        // res是否有then属性函数,有则返回一个绑定res作为this的函数
        if (isResolve && (typeof x === 'object' || typeof x === 'function')) {
            try {
                // 如果x有then方法,则返回一个then函数,this绑定到x,参数是使用thenable函数时thenable函数的参数
                // thenable是一个函数
                thenable = getThen(x);
            } catch (e) {
                return executeCallback.bind(this)('reject', e);
            }
        }
        if (isResolve && thenable) {
            // 递归执行resolve(res)的res.then方法,并绑定this到第一个res上
            // 一开始this指向最外层的promise,所以执行完resolve后就能执行then了
            // 这里执行this所在的then
            executeResolver.bind(this)(thenable);
        } else {
            this.state = isResolve ? RESOLVED : REJECTED;
            this.data = x;
            this.callbackQueue.forEach(v => v[type](x));
        }
        return this;
    }
    //
    function executeResolver(resolver) {
        var called = false,
        // 把this存起来,让执行onSuccess还能访问到这个promise对象的属性
            _this = this;
        // 执行reject,没有返回
        function onError(y) {
            if (called) {
                return; }
            called = true;
            executeCallback.bind(_this)('reject', y);
        }
        // 执行resolve函数, 这里的执行不知道是什么时候的执行,因为是异步的
        // 这个函数是由用户去触发执行的,就是那个resolve(res);
        function onSuccess(r) {
            if (called) {
                return; }
            called = true;
            // 一开始this指向最外层的promise,所以执行完resolve后就能执行then了
            executeCallback.bind(_this)('resolve', r);
        }
        try {
            // 执行成功的函数是由封装的函数作为一个参数提供给用户使用的
            resolver(onSuccess, onError);
        } catch (e) {
            onError(e);
        }
    }

    function executeCallbackAsync(callback, value) {
        var _this = this;
        setTimeout(function() {
            var res;
            try {
                res = callback(value);
            } catch (e) {
                return executeCallback.bind(_this)('reject', e);
            }

            if (res !== _this) {
                return executeCallback.bind(_this)('resolve', res);
            } else {
                return executeCallback.bind(_this)('reject', new TypeError('Cannot resolve promise with itself'));
            }
        }, 4)
    }
    // 构建promise对象,并递归将resolver的resolve(res)的res的then函数递归执行完
    // 所以多层promise是优先执行最深层的then,再执行最外层的then
    // 具体如:
    /* var aa = new Promise().then();
    var bb = new Promise((resolve, reject) => {
      resolve(aa)
    }).then();
    var cc = new Promise((resolve, reject) => {
      resolve(bb)
    }).then();
    */
    // 会优先执行完aa的then,再执行完bb的then,最后再执行完cc的then
    function Promise(resolver) {
        if (resolver && typeof resolver !== 'function') {
            throw new Error('Promise resolver is not a function') }
        this.state = PENDING;
        this.data = UNDEFINED;
        this.callbackQueue = [];

        if (resolver) executeResolver.call(this, resolver);
    }
    Promise.prototype.then = function(onResolved, onRejected) {
        if (typeof onResolved !== 'function' && this.state === RESOLVED ||
            typeof onRejected !== 'function' && this.state === REJECTED) {
            return this;
        }
        // then要重新生成一个promise,但又不能马上执行,因为要判断这个promise执行完了没。promise是异步的
        var promise = new this.constructor();

        if (this.state !== PENDING) {
            var callback = this.state === RESOLVED ? onResolved : onRejected;
            // 通过bind绑定this到新的promise,这样完成了promise的循环。注意这个this.data,是上一个promise执行的结果
            executeCallbackAsync.bind(promise)(callback, this.data);
        } else {
            this.callbackQueue.push(new CallbackItem(promise, onResolved, onRejected))
        }
        // 执行完所有的resolve后,返回旧的promise,这个promise里面保存有上一个then执行完的值。在执行到下一个then前,会判断是否有then,有则将结果返回给then并执行
        return promise;
    }
    Promise.prototype['catch'] = function(onRejected) {
        return this.then(null, onRejected);
    }

    Promise.prototype.wait = function(ms) {
        var P = this.constructor;
        return this.then(function(v) {
            return new P(function(resolve, reject) {
                setTimeout(function() { resolve(v); }, ~~ms)
            })
        }, function(r) {
            return new P(function(resolve, reject) {
                setTimeout(function() { reject(r); }, ~~ms)
            })
        })
    }
    Promise.prototype.always = function(fn) {
        return this.then(function(v) {
            return fn(v), v;
        }, function(r) {
            throw fn(r), r;
        })
    }
    Promise.prototype.done = function(onResolved, onRejected) {
        this.then(onResolved, onRejected).catch(function(error) {
            setTimeout(function() {
                throw error;
            }, 0);
        });
    }

    Promise.resolve = function(value) {
        if (value instanceof this) return value;
        return executeCallback.bind(new this())('resolve', value);
    }
    Promise.reject = function(value) {
        if (value instanceof this) return value;
        return executeCallback.bind(new this())('reject', value);
    }
    Promise.all = function(iterable) {
        var _this = this;
        return new this(function(resolve, reject) {
            if (!iterable || !Array.isArray(iterable)) return reject(new TypeError('must be an array'));
            var len = iterable.length;
            if (!len) return resolve([]);

            var res = Array(len),
                counter = 0,
                called = false;

            iterable.forEach(function(v, i) {
                (function(i) {
                    _this.resolve(v).then(function(value) {
                        res[i] = value;
                        if (++counter === len && !called) {
                            called = true;
                            return resolve(res)
                        }
                    }, function(err) {
                        if (!called) {
                            called = true;
                            return reject(err);
                        }
                    })
                })(i)
            })
        })
    }
    Promise.race = function(iterable) {
        var _this = this;
        return new this(function(resolve, reject) {
            if (!iterable || !Array.isArray(iterable)) return reject(new TypeError('must be an array'));
            var len = iterable.length;
            if (!len) return resolve([]);

            var called = false;
            iterable.forEach(function(v, i) {
                _this.resolve(v).then(function(res) {
                    if (!called) {
                        called = true;
                        return resolve(res);
                    }
                }, function(err) {
                    if (!called) {
                        called = true;
                        return reject(err);
                    }
                })
            })
        })
    }
    Promise.stop = function() { return new this(); }
    Promise.deferred = Promise.defer = function() {
        var dfd = {};
        dfd.promise = new Promise(function(resolve, reject) {
            dfd.resolve = resolve;
            dfd.reject = reject;
        })
        return dfd
    }
    Promise.timeout = function(promise, ms) {
        return this.race([promise, this.reject(new TimeoutError('Operation timed out after ' + ms + ' ms')).wait(ms)]);
    }
    Promise.sequence = function(tasks) {
        return tasks.reduce(function(prev, next) {
            return prev.then(next).then(function(res) {
                return res });
        }, this.resolve());
    }


    function TimeoutError(message) {
        this.message = message || '';
        this.stack = (new Error()).stack;
    }
    TimeoutError.prototype = Object.create(Error.prototype);
    TimeoutError.prototype.constructor = TimeoutError;
    if(!scope.TimeoutError) scope.TimeoutError = TimeoutError;

    try {
        module.exports = Promise;
    } catch (e) {
        if (scope.Promise && !scope.MPromise) scope.MPromise = Promise;
    }
    return Promise;
})(this)

引用:
深入理解 Promise (上)
深入理解 Promise (中)
深入理解 Promise (下)

@cisen
Copy link
Owner Author

cisen commented Jan 15, 2019

最简单实现

  // 如果有obj有then属性函数,则返回一个then函数,this绑定到obj,接受使用then时的参数
  function getThen(obj) {
      var then = obj && obj.then;
      if (obj && typeof obj === 'object' && typeof then === 'function') {
          return function appyThen() {
              // this绑定到boj并执行then方法
              then.apply(obj, arguments);
          };
      }
  }
// 如果resolve(res)的res还是一个promise,则先执行完自己的resolve,再继续执行res的then方法,this绑定到res
  // 这里可以将res的所有then方法递归完
  function executeCallback(type, x) {
      var isResolve = type === 'resolve',
          thenable;
      // 如果客户使用resolve(res)时,res是一个函数或者对象,x就是res,则去判断
      // res是否有then属性函数,有则返回一个绑定res作为this的函数
      if (isResolve && (typeof x === 'object' || typeof x === 'function')) {
          try {
              // 如果x有then方法,则返回一个then函数,this绑定到x,参数是使用thenable函数时thenable函数的参数
              // thenable是一个函数
              thenable = getThen(x);
          } catch (e) {
              return executeCallback.bind(this)('reject', e);
          }
      }
      if (isResolve && thenable) {
          // 递归执行resolve(res)的res.then方法,并绑定this到第一个res上
          // 一开始this指向最外层的promise,所以执行完resolve后就能执行then了
          // 这里执行this所在的then
          executeResolver.bind(this)(thenable);
      } else {
          this.state = isResolve ? RESOLVED : REJECTED;
          this.data = x;
          this.callbackQueue.forEach(v => v[type](x));
      }
      return this;
  }
// 用于执行 new Promise(function(resolve, reject){}) 中的resove或reject方法
  function executeResolver(resolver) {
      //[标准 2.3.3.3.3] 如果resove()方法多次调用,只响应第一次,后面的忽略
      var called = false,
      // 把this存起来,让执行onSuccess还能访问到这个promise对象的属性
          _this = this;
      // 执行reject,没有返回
      function onError(y) {
          if (called) {
              return; }
          called = true;
          //[标准 2.3.3.3.2] 如果是错误 使用reject方法
          executeCallback.bind(_this)('reject', y);
      }
      // 执行resolve函数, 这里的执行不知道是什么时候的执行,因为是异步的
      // 这个函数是由用户去触发执行的,就是那个resolve(res);
      function onSuccess(r) {
          if (called) {
              return; }
          called = true;
          // 一开始this指向最外层的promise,所以执行完resolve后就能执行then了
          executeCallback.bind(_this)('resolve', r);
      }
      try {
          // 执行成功的函数是由封装的函数作为一个参数提供给用户使用的
          //[标准 2.3.3.3.4] 如果调用resolve()或reject()时发生错误,则将状态改成rejected,并将错误reject出去
          resolver(onSuccess, onError);
      } catch (e) {
          onError(e);
      }
  }

function Promise(resolver) {
      if (resolver && typeof resolver !== 'function') {
          throw new Error('Promise resolver is not a function') }
      // PENDING Fulfilled  Rejected
      this.state = PENDING;
      //当前promise对象的数据(成功或失败)
      this.data = UNDEFINED;
      //当前promise对象注册的回调队列
      this.callbackQueue = [];

      if (resolver) executeResolver.call(this, resolver);
  }
  Promise.prototype.then = function(onResolved, onRejected) {
      if (typeof onResolved !== 'function' && this.state === RESOLVED ||
          typeof onRejected !== 'function' && this.state === REJECTED) {
          return this;
      }

      var promise = new this.constructor();

      if (this.state !== PENDING) {
          var callback = this.state === RESOLVED ? onResolved : onRejected;
          executeCallbackAsync.bind(promise)(callback, this.data);
      } else {
          this.callbackQueue.push(new CallbackItem(promise, onResolved, onRejected))
      }
      // 链式调用
      return promise;
  }
  Promise.prototype['catch'] = function(onRejected) {
      return this.then(null, onRejected);
  }
# 总结
1. resolve函数执行的时候通过`var promise = new this.constructor();`生成一个promise返回
2. resolve之后是如何切换到then的,这是一个问题

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant