promise是何物

日期:2016-3-22 20:51 | 标签: promise javascript | 阅读:945

Promise 该算是2015年前端界的十大热词之一吧。关于 Promise 的介绍实在太多,这里主要总结一些主流框架中 Promise 的用法,以及结合自己思考,手写的一个 Promise 实现。

Promise 是什么

Promise 是一种 JavaScript 异步编程模式,我的第一感觉是再也不用进回调地狱了,其很大程度上提升编程俺们的编程效率。

AngularJS中 Promise 用法

引自angularjs doc,$q为内置对象实现。

// for the purpose of this example let's assume that variables `$q` and `okToGreet`
// are available in the current lexical scope (they could have been injected or passed in).
function asyncGreet(name) {
  // perform some asynchronous operation, resolve or reject the promise when appropriate.
  return $q(function(resolve, reject) {
    setTimeout(function() {
       if (okToGreet(name)) {
           resolve('Hello, ' + name + '!');
       } else {
          reject('Greeting ' + name + ' is not allowed.');
      }
    }, 1000);
  });
}
var promise = asyncGreet('Robin Hood');
promise.then(function(greeting) {
   alert('Success: ' + greeting);
}, function(reason) {
   alert('Failed: ' + reason);
});

// 结合$http使用案例
var d = $q.defer();
$http({
    method: 'GET',
    url: "url",
}).success(function(data) {
        d.resolve(data);
}).error(function(err) {
        d.reject(err);
});
return d.promise;

JQuery中 Promise 用法

Deferred 对象(引自阮一峰博客)

    var dtd = $.Deferred(); // 新建一个Deferred对象
  var wait = function(dtd){
    var tasks = function(){
      alert("执行完毕!");
      dtd.resolve(); // 改变Deferred对象的执行状态
    };
    setTimeout(tasks,5000);
    return dtd.promise(); // 返回promise对象
  };
  var d = wait(dtd); // 新建一个d对象,改为对这个对象进行操作
  $.when(d)
  .done(function(){ alert("哈哈,成功了!"); })
  .fail(function(){ alert("出错啦!"); });
  d.resolve(); // 此时,这个语句是无效的

1.8以后

var promise = $.ajax({
  url: "/ServerResource.txt"
});
promise.then(successFunction, errorFunction);
//如果不想处理某个事件类型,可以传入Null
var promise = $.ajax({
  url: "/ServerResource.txt"
});
promise.then(successFunction); // no handler for the fail() event

对于多个并发的请求,可以使用

$.when(ajax1,ajax2)
.done(function(data1,data2){
// todo
})
.fail(function(err){
// todo
})

ExtJS promise用法

 function getAjax (url) {
     // The function passed to Ext.Promise() is called immediately to start
     // the asynchronous action.
     //
     return new Ext.Promise(function (resolve, reject) {
         Ext.Ajax.request({
             url: url,
             success: function (response) {
                 // Use the provided "resolve" method to deliver the result.
                 //
                 resolve(response.responseText);
             },
             failure: function (response) {
                 // Use the provided "reject" method to deliver error message.
                 //
                 reject(response.status);
             }
         });
     });
 }
 getAjax('http://stuff').then(function (content) {
     // content is responseText of ajax response
 });

动手实现

看了上述框架中 Promise 用法,可以说是大同小异,因为他们基本上都遵循当主流的 Promise 规范,比如

本来我还想动手,哪知网上有诸多实现,关于promise需求分析也有很多:

最终还是决定看懂源码,理解原理作罢,代码参考这个吧,写得不错,该考虑的都考虑到了,也就200多行代码( 符合Promises/A+ 规范 ):
promise-polyfill-github

使用示例

var prom = new Promise(function(resolve, reject) {
  // do a thing, possibly async, then…

   if (/* everything turned out fine */) {
     resolve("Stuff worked!");
   }  else {
     reject(new Error("It broke"));
  }
});

// Do something when async done
prom.then(function() {
  ...
});

构造函数实现片段

function Promise(fn) {
    if (typeof this !== 'object') throw new TypeError('Promises must be constructed via new');
    if (typeof fn !== 'function') throw new TypeError('not a function');
    this._state = 0;
    this._handled = false;
    this._value = undefined;
    this._deferreds = [];

    doResolve(fn, this);
  }

doResolve实现片段,处理 Promise 参数对象

 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);
    }
  }

resolve实现片段,开启成功处理流程

function resolve(self, newValue) {
    try {
      // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
      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') { // Promise 对象
           doResolve(bind(then, newValue), self);
           return;
        }
      }
       self._state = 1;
       self._value = newValue;
       finale(self);
    } catch (e) {
       reject(self, e);
    }
  }

then片段,开启后续流程

Promise.prototype.then = function (onFulfilled, onRejected) {
    var prom = new Promise(noop);
    handle(this, new Handler(onFulfilled, onRejected, prom));
    return prom;
  };

handle片段,循环检测与处理

function handle(self, deferred) {
    while (self._state === 3) {
      self = self._value;
    }
    if (self._state === 0) {
      self._deferreds.push(deferred);
      return;
    }
    self._handled = true;
    asap(function () { // 立即执行
      var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
      if (cb === null) {
        (self._state === 1 ? resolve : reject)(deferred.promise, self._value);
        return;
      }
      var ret;
      try {
        ret = cb(self._value);
      } catch (e) {
        reject(deferred.promise, e);
        return;
      }
      resolve(deferred.promise, ret);
    });
  }

参考

版权声明: 署名-非商业性使用-禁止演绎 4.0 国际(CC BY-NC-ND 4.0
Copyright ©2013-2017 | 粤ICP备14081691号 | yipeng手工打造 | 联系方式