WEEX H5 Render 解读(7)之promise类续

上节我们已t经阅读了promise.js的代码,了解了weex对promise基本的封装。今天我们来阅读下,weex是如何支持promise写法的。按照昨天的图,找到源码。
WEEX H5 Render 解读(7)之promise类续_第1张图片

这个文件的代码有点长,我们先看一下整体代码,然后我将一点一点分析

'use strict';
var immediate = require('immediate');

/* istanbul ignore next */
function INTERNAL() {}

var handlers = {};

var REJECTED = ['REJECTED'];
var FULFILLED = ['FULFILLED'];
var PENDING = ['PENDING'];
/* istanbul ignore else */
if (!process.browser) {
  // in which we actually take advantage of JS scoping
  var UNHANDLED = ['UNHANDLED'];
}

module.exports = Promise;

function Promise(resolver) {
  if (typeof resolver !== 'function') {
    throw new TypeError('resolver must be a function');
  }
  this.state = PENDING;
  this.queue = [];
  this.outcome = void 0;
  /* istanbul ignore else */
  if (!process.browser) {
    this.handled = UNHANDLED;
  }
  if (resolver !== INTERNAL) {
    safelyResolveThenable(this, resolver);
  }
}

Promise.prototype.catch = function (onRejected) {
  return this.then(null, onRejected);
};
Promise.prototype.then = function (onFulfilled, onRejected) {
  if (typeof onFulfilled !== 'function' && this.state === FULFILLED ||
    typeof onRejected !== 'function' && this.state === REJECTED) {
    return this;
  }
  var promise = new this.constructor(INTERNAL);
  /* istanbul ignore else */
  if (!process.browser) {
    if (this.handled === UNHANDLED) {
      this.handled = null;
    }
  }
  if (this.state !== PENDING) {
    var resolver = this.state === FULFILLED ? onFulfilled : onRejected;
    unwrap(promise, resolver, this.outcome);
  } else {
    this.queue.push(new QueueItem(promise, onFulfilled, onRejected));
  }

  return promise;
};
function QueueItem(promise, onFulfilled, onRejected) {
  this.promise = promise;
  if (typeof onFulfilled === 'function') {
    this.onFulfilled = onFulfilled;
    this.callFulfilled = this.otherCallFulfilled;
  }
  if (typeof onRejected === 'function') {
    this.onRejected = onRejected;
    this.callRejected = this.otherCallRejected;
  }
}
QueueItem.prototype.callFulfilled = function (value) {
  handlers.resolve(this.promise, value);
};
QueueItem.prototype.otherCallFulfilled = function (value) {
  unwrap(this.promise, this.onFulfilled, value);
};
QueueItem.prototype.callRejected = function (value) {
  handlers.reject(this.promise, value);
};
QueueItem.prototype.otherCallRejected = function (value) {
  unwrap(this.promise, this.onRejected, value);
};

function unwrap(promise, func, value) {
  immediate(function () {
    var returnValue;
    try {
      returnValue = func(value);
    } catch (e) {
      return handlers.reject(promise, e);
    }
    if (returnValue === promise) {
      handlers.reject(promise, new TypeError('Cannot resolve promise with itself'));
    } else {
      handlers.resolve(promise, returnValue);
    }
  });
}

handlers.resolve = function (self, value) {
  var result = tryCatch(getThen, value);
  if (result.status === 'error') {
    return handlers.reject(self, result.value);
  }
  var thenable = result.value;

  if (thenable) {
    safelyResolveThenable(self, thenable);
  } else {
    self.state = FULFILLED;
    self.outcome = value;
    var i = -1;
    var len = self.queue.length;
    while (++i < len) {
      self.queue[i].callFulfilled(value);
    }
  }
  return self;
};
handlers.reject = function (self, error) {
  self.state = REJECTED;
  self.outcome = error;
  /* istanbul ignore else */
  if (!process.browser) {
    if (self.handled === UNHANDLED) {
      immediate(function () {
        if (self.handled === UNHANDLED) {
          process.emit('unhandledRejection', error, self);
        }
      });
    }
  }
  var i = -1;
  var len = self.queue.length;
  while (++i < len) {
    self.queue[i].callRejected(error);
  }
  return self;
};

function getThen(obj) {
  // Make sure we only access the accessor once as required by the spec
  var then = obj && obj.then;
  if (obj && typeof obj === 'object' && typeof then === 'function') {
    return function appyThen() {
      then.apply(obj, arguments);
    };
  }
}

function safelyResolveThenable(self, thenable) {
  // Either fulfill, reject or reject with error
  var called = false;
  function onError(value) {
    if (called) {
      return;
    }
    called = true;
    handlers.reject(self, value);
  }

  function onSuccess(value) {
    if (called) {
      return;
    }
    called = true;
    handlers.resolve(self, value);
  }

  function tryToUnwrap() {
    thenable(onSuccess, onError);
  }

  var result = tryCatch(tryToUnwrap);
  if (result.status === 'error') {
    onError(result.value);
  }
}

function tryCatch(func, value) {
  var out = {};
  try {
    out.value = func(value);
    out.status = 'success';
  } catch (e) {
    out.status = 'error';
    out.value = e;
  }
  return out;
}

Promise.resolve = resolve;
function resolve(value) {
  if (value instanceof this) {
    return value;
  }
  return handlers.resolve(new this(INTERNAL), value);
}

Promise.reject = reject;
function reject(reason) {
  var promise = new this(INTERNAL);
  return handlers.reject(promise, reason);
}

Promise.all = all;
function all(iterable) {
  var self = this;
  if (Object.prototype.toString.call(iterable) !== '[object Array]') {
    return this.reject(new TypeError('must be an array'));
  }

  var len = iterable.length;
  var called = false;
  if (!len) {
    return this.resolve([]);
  }

  var values = new Array(len);
  var resolved = 0;
  var i = -1;
  var promise = new this(INTERNAL);

  while (++i < len) {
    allResolver(iterable[i], i);
  }
  return promise;
  function allResolver(value, i) {
    self.resolve(value).then(resolveFromAll, function (error) {
      if (!called) {
        called = true;
        handlers.reject(promise, error);
      }
    });
    function resolveFromAll(outValue) {
      values[i] = outValue;
      if (++resolved === len && !called) {
        called = true;
        handlers.resolve(promise, values);
      }
    }
  }
}

Promise.race = race;
function race(iterable) {
  var self = this;
  if (Object.prototype.toString.call(iterable) !== '[object Array]') {
    return this.reject(new TypeError('must be an array'));
  }

  var len = iterable.length;
  var called = false;
  if (!len) {
    return this.resolve([]);
  }

  var i = -1;
  var promise = new this(INTERNAL);

  while (++i < len) {
    resolver(iterable[i]);
  }
  return promise;
  function resolver(value) {
    self.resolve(value).then(function (response) {
      if (!called) {
        called = true;
        handlers.resolve(promise, response);
      }
    }, function (error) {
      if (!called) {
        called = true;
        handlers.reject(promise, error);
      }
    });
  }
}



/** WEBPACK FOOTER **
 ** ./~/lie/lib/index.js
 **/

这个代码里主要有Promise,QueueItem,handler这三个类。

  • Promise类型定义
function Promise(resolver) { if (typeof resolver !== 'function') { throw new TypeError('resolver must be a function'); } this.state = PENDING; this.queue = []; this.outcome = void 0; /* istanbul ignore else */ if (!process.browser) { this.handled = UNHANDLED; } if (resolver !== INTERNAL) { safelyResolveThenable(this, resolver); }}

我们可以看到在实例化promise类时,需要传进一个参数resolver,这个值是函数类型。

  • Promise原型扩展定义
    代码中所有Promise.prototype.XXX的代码所定义的方法,让我们在每个实例中都可以调用catch,then 的方法。例如:
var resoler=function (resolve, reject) {
      setTimeout(function(){
          return resolve(20);
      },20);
}
var dd=new Promise(resoler);
dd.then(function(data){
    console.log(data);
},function(data){
    console.log(data);
});
  • Promise静态方法扩展。称呼可能有点问题
    代码中所有Promise.XXX中的方法是可以静态调用的。例如:
        var fun=function(param){
            if(param ==true){
                return Promise.resolve(true);
            }else{
                return Promise.reject(false);
            }
        };
        fun(true).then(function(data){
            console.log(data);
        },function(data){
            console.log(data);
        });
  • QueueItem内部类,何为内部类呢?就是你在别的文件无法访问到的js类
function QueueItem(promise, onFulfilled, onRejected) {
  this.promise = promise;
  if (typeof onFulfilled === 'function') {
    this.onFulfilled = onFulfilled;
    this.callFulfilled = this.otherCallFulfilled;
  }
  if (typeof onRejected === 'function') {
    this.onRejected = onRejected;
    this.callRejected = this.otherCallRejected;
  }
}
QueueItem.prototype.callFulfilled = function (value) { 
    handlers.resolve(this.promise, value);
};
QueueItem.prototype.otherCallFulfilled = function (value) {
     unwrap(this.promise, this.onFulfilled, value);
};
QueueItem.prototype.callRejected = function (value) { 
    handlers.reject(this.promise, value);
};
QueueItem.prototype.otherCallRejected = function (value) { 
    unwrap(this.promise, this.onRejected, value);
};

其实QueueItem就是一个promise执行单元,用于连接weex运行时和我们写的promise函数中的then函数。将《在weex原理解读》中深入讲解业务逻辑代码与weex运行时连接的

  • handler控制器方法
handlers.resolve = function (self, value) { var result = tryCatch(getThen, value); if (result.status === 'error') { return handlers.reject(self, result.value); } var thenable = result.value; if (thenable) { safelyResolveThenable(self, thenable); } else { self.state = FULFILLED; self.outcome = value; var i = -1; var len = self.queue.length; while (++i < len) { self.queue[i].callFulfilled(value); } } return self;};handlers.reject = function (self, error) { self.state = REJECTED; self.outcome = error; /* istanbul ignore else */ if (!process.browser) { if (self.handled === UNHANDLED) { immediate(function () { if (self.handled === UNHANDLED) { process.emit('unhandledRejection', error, self); } }); } } var i = -1; var len = self.queue.length; while (++i < len) { self.queue[i].callRejected(error); } return self;};

handler的方法主要是用于控制当前的执行状态,用以决定该执行promise的哪个函数。

你可能感兴趣的:(WEEX H5 Render 解读(7)之promise类续)