這裏不解釋promise是什麼,由於我相信你來看文章的時候已經知道你什麼是promise了。
此處有promise規範。程序員
Promise/A+規範 中文
Promise/A+
ES2016:MDN Promisesegmentfault
$q是AngularJS提供的一個服務。promise
$q是跟AngularJS的$rootScope模板集成的,因此在AngularJS中執行和拒絕都很快。(編輯器瘋了,dollar符號就是打不出來,就叫 'dollar'q)app
$q是跟AngularJS模板引擎集成的,這意味着在視圖中找到任何Promise都會在視圖中被執行或者拒絕。異步
直接上栗子,程序員都不喜歡聽你廢話~〒▽〒編輯器
var app = angular.module('app', []) .controller('testController', function ($scope, $q) { //定義一個defer var defer = $q.defer(); var promise = defer.promise; promise.then(function (data) { //成功後的邏輯處理 }, function (error) { //失敗後的邏輯處理 }); //模擬經過--實際應該是一個異步的callback中調用 defer.resolve('[data]'); //模擬拒絕--實際應該是一個異步的callback中調用 defer.reject('[data]'); });
then會返回一個新的promise對象,因此直接jQuery風格的鏈式調用。
仍是直接上栗子:函數
var app = angular.module('app', []) .controller('testController', function ($scope, $q) { //定義一個defer var defer = $q.defer(); var promise = defer.promise; promise.then(function () { console.log('then-resolved-1'); }, function () { console.log('then-rejected-1'); }) .then(function () { console.log('then-resolved-2'); }, function () { console.log('then-rejected-2'); }); //模擬經過--實際應該是一個異步的callback中調用 defer.resolve('[data]'); //模擬拒絕--實際應該是一個異步的callback中調用 defer.reject('[data]'); });
來看下是如何實現鏈式調用的,下面是AngularJS源碼實現:this
//angular.js Promise.prototype = { then: function(onFulfilled, onRejected, progressBack) { var result = new Deferred();//此處能夠看出,每一個then都會返回一個新的Deferred對象。 this.$$state.pending = this.$$state.pending || []; this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]); if (this.$$state.status > 0) scheduleProcessQueue(this.$$state); return result.promise; }, //其餘省略 ... } //Deferred定義 function Deferred() { this.promise = new Promise();//能夠看到defer的promise對象是一個new Promise() //Necessary to support unbound execution :/ this.resolve = simpleBind(this, this.resolve); this.reject = simpleBind(this, this.reject); this.notify = simpleBind(this, this.notify); }
看過上面鏈式調用的栗子和AngularJS的源碼後,你們就能知道每一個then的上下文實際上是不同的,由於每次都是新new 出來的Promise對象。
先給栗子:prototype
var app = angular.module('app', []) .controller('testController', function ($scope, $q) { //定義一個defer var defer = $q.defer(); var promise = defer.promise; promise.then(function (data) { //... return data;// data = 1 }, function (error) { //... }) .then(function (data) { //... return data;//data = 1 }, function (error) { //... }); //模擬經過--實際應該是一個異步的callback中調用 defer.resolve('1'); });
接下來看一段源碼解析,看看AngularJS是如何調用Promise的。code
//angular.js Deferred.prototype = { resolve: function(val) { if (this.promise.$$state.status) return; if (val === this.promise) { this.$$reject($qMinErr( 'qcycle', "Expected promise to be resolved with value other than itself '{0}'", val)); } else { this.$$resolve(val);//實際調用這個方法 } }, $$resolve: function(val) { var then, fns; fns = callOnce(this, this.$$resolve, this.$$reject); try { if ((isObject(val) || isFunction(val))) then = val && val.then; if (isFunction(then)) { this.promise.$$state.status = -1; then.call(val, fns[0], fns[1], this.notify); } else { this.promise.$$state.value = val; this.promise.$$state.status = 1; scheduleProcessQueue(this.promise.$$state);//最終在此處加入到隊列中 } } catch (e) { fns[1](e); exceptionHandler(e); } },... //scheduleProcessQueue定義 function scheduleProcessQueue(state) { if (state.processScheduled || !state.pending) return; state.processScheduled = true; nextTick(function() { processQueue(state); });//此處調用進入processQueue } function processQueue(state) { var fn, promise, pending; pending = state.pending; state.processScheduled = false; state.pending = undefined; for (var i = 0, ii = pending.length; i < ii; ++i) { promise = pending[i][0]; fn = pending[i][state.status]; try { if (isFunction(fn)) { promise.resolve(fn(state.value));//此處是鏈式調用傳參關鍵,fn(state.value)實際是上一個then的resolve的返回值,因此能知道,若是須要全部的then都能取到異步任務的返回值,就得在then的resolve函數中,將值返回。 } else if (state.status === 1) { promise.resolve(state.value); } else { promise.reject(state.value); } } catch (e) { promise.reject(e); exceptionHandler(e); } } }