完全copy from vue-resource (The HTTP client for Vue.js)
https://github.com/pagekit/vue-resource
理解这个实现,则对promise的语法就不难理解了,不然一直云里雾里的死记硬背语法。
1.1 promise构造函数
/*** Promises/A+ polyfill v1.1.4 (https://github.com/bramstein/promis)*/// 根据promise对象的三种状态定义三个常量var RESOLVED = 0;var REJECTED = 1;var PENDING = 2;// 构造函数function Promise$1(executor) {this.state = PENDING; // 初始化实例状态为pendingthis.value = undefined; // 操作结果,初始化为undefinedthis.deferred = []; // 延迟操作数组,既then()添加的成功or失败函数var promise = this; // 保存this指向,在引入的操作函数中用try {executor(function (x) { // 执行操作,并传入实例的resolve/reject方法promise.resolve(x); // 当传入的操作明确执行成功,调用实例resolve方法}, function (r) {promise.reject(r); // 当传入的操作明确执行失败,调用实例reject方法});} catch (e) {promise.reject(e); // 当操作执行过程中,语法或其他意外错误,同样调用实例reject方法}}
1.2 原型上挂载的方法
var p$1 = Promise$1.prototype; // 原型p$1.resolve = function resolve(x) {var promise = this;if (promise.state === PENDING) {if (x === promise) {throw new TypeError('Promise settled with itself.');}var called = false;try {var then = x && x['then'];// 如果操作结果返回的x是另一个promise实例,则当前promise实例的状态则重新由// 返回的promise实例的状态来决定if (x !== null && typeof x === 'object' && typeof then === 'function') {then.call(x, function (x) { // 调用返回的实例的then方法,获取返回的实例的状态if (!called) {promise.resolve(x); // 成功,则执行当前实例的resolve,并返回} // 返回的实例的执行结果called = true;}, function (r) {if (!called) {promise.reject(r); // 失败}called = true;});return;}} catch (e) {if (!called) {promise.reject(e);}return;}//当执行结果是普通(非promise实例)结果,才会走到这一步,改变状态且执行延迟操作promise.state = RESOLVED; // 实例状态从pendding-->fulfiledpromise.value = x; // 把操作结果挂载到实例上promise.notify(); // 触发实例上挂载的延迟操作}};p$1.reject = function reject(reason) {var promise = this;if (promise.state === PENDING) {if (reason === promise) {throw new TypeError('Promise settled with itself.');}// 同上promise.state = REJECTED;promise.value = reason;promise.notify();}};// 触发通过then方法挂载到实例上的延迟操作// 两种情况会触发,1 操作有结果时,调用resolve/reject实例方法会触发// 2 调用then实例方法,挂载延迟操作时,会触发,这样可以保证操作和回调解耦的情况下,回调能执行。p$1.notify = function notify() {var promise = this;// nextTick既微任务队列,vue-resouure里面的nextTick直接使用的Vue里面提供的Vue.nextTick,// Vue里面则根据浏览器宿主环境选择原生promise或者Observe以及setTImeoutnextTick(function () {// 只有状态变化才会执行队列if (promise.state !== PENDING) {while (promise.deferred.length) { // 遍历延迟操作数组var deferred = promise.deferred.shift(),onResolved = deferred[0],onRejected = deferred[1],resolve = deferred[2],reject = deferred[3];try {if (promise.state === RESOLVED) { // 成功延迟操作if (typeof onResolved === 'function') {// 注意:这里的resolve是then方法调用生成的新的promise实例,//所以这里返回的是新实例的结果resolve(onResolved.call(undefined, promise.value));} else {// 如果函数未传入,则把结果向后推送resolve(promise.value);}} else if (promise.state === REJECTED) { // 失败延迟操作if (typeof onRejected === 'function') {// 同理,reject也是新实例的方法,如果处理了失败,// 失败状态不会向下传递,且新的实例状态为fullfiedresolve(onRejected.call(undefined, promise.value));} else {//否则,失败结果会向下传递,这也是为什么失败延迟操作,可以捕获链式// 调用中,某一环节未被处理的错误reject(promise.value);}}} catch (e) {reject(e);}}}});};// 挂载延迟操作回调p$1.then = function then(onResolved, onRejected) {var promise = this;// 返回一个新的实例return new Promise$1(function (resolve, reject) {// 向旧的实例的延迟操作队列中push新的promise.deferred.push([onResolved, onRejected, resolve, reject]);// 触发执行队列promise.notify();});};p$1.catch = function (onRejected) {return this.then(undefined, onRejected);};
1.3构造函数挂载的方法
//构造函数挂载的reject,用于快速生成一个明确pendding->failed的实例Promise$1.reject = function (r) {return new Promise$1(function (resolve, reject) {reject(r);});};//构造函数挂载的reject,用于快速生成一个明确pendding->fullfied的实例Promise$1.resolve = function (x) {return new Promise$1(function (resolve, reject) {resolve(x);});};Promise$1.all = function all(iterable) {return new Promise$1(function (resolve, reject) {var count = 0,result = [];if (iterable.length === 0) {resolve(result);}function resolver(i) {return function (x) {result[i] = x;count += 1;if (count === iterable.length) {resolve(result);}};}for (var i = 0; i < iterable.length; i += 1) {Promise$1.resolve(iterable[i]).then(resolver(i), reject);}});};Promise$1.race = function race(iterable) {return new Promise$1(function (resolve, reject) {for (var i = 0; i < iterable.length; i += 1) {Promise$1.resolve(iterable[i]).then(resolve, reject);}});};
