你尚未登录,仅允许查看本站部分内容。请登录使用邀请码注册
Traveller

从promise-polyfill.js实现看Promise应用时注意点 0个回复 专栏 @ Javascript

Traveller 发布于 1 月前

resolve/reject只能接收一个传值

工作中封装一个ajax请求简写方法,想API返回正常情况值时(code===200),直接.then里调用data数据.异常时,在catch里传递三个参数msg, code, date.
写完后,发现.catch后面两个参数调用时始终是undefined.网上查了下资料,原来resolve/reject只能接收一个值传递.要实现多参数只能变相通过对象或数组来显现.

//https://github.com/taylorhakes/promise-polyfill/blob/master/dist/polyfill.js#L149
function doResolve(fn, self) {
  var done = false;
  try {
    fn(
      function(value) {  //只接收一个传值
        if (done) return;
        done = true;
        resolve(self, value);
      },
      function(reason) {   //只接收一个传值
        if (done) return;
        done = true;
        reject(self, reason);
      }
    );
  } catch (ex) {
    if (done) return;
    done = true;
    reject(self, ex);
  }
}

//https://github.com/taylorhakes/promise-polyfill/blob/master/dist/polyfill.js#L85
function resolve(self, newValue) {
  try {
    if (newValue === self)
      throw new TypeError('A promise cannot be resolved with itself.');
    if (
      newValue &&
      (typeof newValue === 'object' || typeof newValue === 'function')
    ) {
      var then = newValue.then;
      if (newValue instanceof Promise) {
        self._state = 3;
        self._value = newValue;     
        finale(self);
        return;
      } else if (typeof then === 'function') {
        doResolve(bind(then, newValue), self);
        return;
      }
    }
   // 上面逻辑解决传递值是一个promise时,则获取该promise决议值
    self._state = 1;
    self._value = newValue;    //保存供第一次then调用
    finale(self);
  } catch (e) {
    reject(self, e);
  }
}

function reject(self, newValue) {
  self._state = 2;
  self._value = newValue;     //保存值待第一次then(null, reject)/catch调用
  finale(self);
}
/*
下面是常用写法,promise-polyfill.js 调用栈Promise -> doResolve -> resolve/reject . 
fn中的两个函数,显然值接收了一个参数value(reject为reason), 
接着在函数内调用resolve/reject,将值用self._value储存.
后续then`第一次`调用则引用self._value值. 
new Promise(fuction(resolve, reject)) {
       ......
       resolve(...args)
       ......
       reject(...args)
       ......
}).then()
*/

链式调用或return一个已使用then的promise,需在前一个then/catch中显示return value

then/catch忽略非函数值,返回调用前的promise(含值)

catch后续调用then,则返回一个新promise,结果为其callback执行结果(异常情况,走后续catch).

// https://github.com/taylorhakes/promise-polyfill/blob/master/dist/polyfill.js#L175
Promise.prototype.then = function(onFulfilled, onRejected) {
  var prom = new this.constructor(noop);
  handle(this, new Handler(onFulfilled, onRejected, prom));   //新的promise,供后面返回
  return prom;
};

// https://github.com/taylorhakes/promise-polyfill/blob/master/dist/polyfill.js#L137
// 非函数值,转换为null
function Handler(onFulfilled, onRejected, promise) {    
  this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
  this.onRejected = typeof onRejected === 'function' ? onRejected : null;
  this.promise = promise;
}

//https://github.com/taylorhakes/promise-polyfill/blob/master/dist/polyfill.js#L59
function handle(self, deferred) {
  while (self._state === 3) {
    self = self._value;
  }
  if (self._state === 0) {
    self._deferreds.push(deferred);
    return;
  }
  self._handled = true;
  Promise._immediateFn(function() {
    var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
    if (cb === null) {           //如果resolve或reject非函数值,则使用前promise
      (self._state === 1 ? resolve : reject)(deferred.promise, self._value);
      return;
    }
    var ret;
    try {                                          
      ret = cb(self._value);                  // catch结果不抛错,作为新promise的resolve值
    } catch (e) {
      reject(deferred.promise, e);
      return;
    }
    resolve(deferred.promise, ret);   // 如果cb没有返回值,则ret为undefined,传给下个promise
  });                                // 即promise.then(calback).then(callback(undefind){...})
}

finally无接收值,返回一个新promise含原promise决议值.(finally callback运行无error)

//https://github.com/taylorhakes/promise-polyfill/blob/master/dist/polyfill.js#L10

function finallyConstructor(callback) {
  var constructor = this.constructor;
  return this.then(
    function(value) {
      return constructor.resolve(callback()).then(function() {
        return value;
      });
    },
    function(reason) {
      return constructor.resolve(callback()).then(function() {
        return constructor.reject(reason);
      });
    }
  );
}

catch与then(null, reject)不完全相同.

如果then中resolve出现异常,则后续的catch处理该异常,非原先promise的reject

promise 不仅解决callback hell问题,更能让我们使用return,throw,栈能力

阅读推荐

谈谈使用 promise 时候的一些反模式

taylorhakes/promise-polyfill.js

等待第一条回复
登录后回复,如无账号,请使用邀请码注册