Promise我想如今你們都很是熟悉了,主要做用就是解決異步回調問題,這裏簡單介紹下。javascript
Promise規範是CommonJS規範之一,而Promise規範又分了好多種,好比 Promises/A、Promises/B、Promises/Kiss等等html
有興趣的能夠到這多瞭解一些 http://wiki.commonjs.org/wiki/Promiseshtml5
如今比較流行的是Promise/A規範,人們對它的完善和擴展,逐漸造成了Promise/A+規範,A+已脫穎而出。java
說到這裏規範是什麼,能夠去這裏瞭解下git
http://promises-aplus.github.io/promises-spec/es6
http://hussion.me/2013/10/19/promises-a/github
如今已有瀏覽器內置支持Promise,它的api語法能夠在這裏查看api
http://www.html5rocks.com/zh/tutorials/es6/promises/#toc-api數組
能夠看到它的api並很少,其實規範也很少,我覺的大體抓住幾個重要的點就夠了,promise
一、promise有三種狀態,等待(pending)、已完成(fulfilled)、已拒絕(rejected)
二、promise的狀態只能從「等待」轉到「完成」或者「拒絕」,不能逆向轉換,同時「完成」和「拒絕」也不能相互轉換
三、promise必須有一個then方法,並且要返回一個promise,供then的鏈式調用,也就是可thenable的
四、then接受倆個回調(成功與拒絕),在相應的狀態轉變時觸發,回調可返回promise,等待此promise被resolved後,繼續觸發then鏈
知道這幾個重要的特色,咱們就能夠參考瀏覽器內置的api來實現了,
咱們能夠沒必要太受規範約束,先按照本身的想法來就行了。
promise的使用大體以下
var promise = new Promise(function(resolve, reject) { setTimeout(function(){ resolve('val') }); }); promise.then(onFulfilled,onRejected).then(onFulfilled,onRejected)
主要思路就是咱們能夠直接對返回的promise對象進行操做,好比then,傳入回調,
這裏的函數並不會當即執行,而是加入隊列,等待將來的某個時間resolve時被觸發執行。
有了以上說明,就能夠來實現了
首先定義三個狀態
var PENDING = undefined, FULFILLED = 1, REJECTED = 2;
而後實現Promise構造函數,此函數接受一個函數參數,函數參數接受倆個咱們提供的方法resolve與reject,
供使用者在將來的某個時間裏調用觸發執行咱們的隊列,這裏還要初始下當前的狀態,傳遞的值,
以及then時保存到的隊列。
大概像下面這樣
var Promise = function(resolver){ if (!isFunction(resolver)) throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); if(!(this instanceof Promise)) return new Promise(resolver); var promise = this; promise._value; promise._reason; promise._status = PENDING; promise._resolves = []; promise._rejects = []; var resolve = function(value){ //狀態轉換爲FULFILLED //執行then時保存到_resolves裏的回調, //若是回調有返回值,更新當前_value } var reject = function(reason){ //狀態轉換爲REJECTED //執行then時保存到_rejects裏的回調, //若是回調有返回值,更新當前_rejects } resolver(resolve,reject); }
有了這個,咱們在實現一個then就ok了,
then裏要作的就是返回一個promise供then的鏈式調用,
並且promise.then(onFulfilled,onRejected)時,咱們要判斷當前promise的狀態,
若是是pending則把onFulfilled與onRejected添加到_resolves與_rejects數組裏,
不然的話根據狀態,直接觸發回調,這裏要注意的是,若是返回的是promise,咱們要等到此promise被resolves時,
觸發then鏈的下一個promise執行。
代碼大概是這樣
Promise.prototype.then = function(onFulfilled,onRejected){ var promise = this; // 每次返回一個promise,保證是可thenable的 return Promise(function(resolve,reject){ function callback(value){ var ret = isFunction(onFulfilled) && onFulfilled(value) || value; if(isThenable(ret)){ // 根據返回的promise執行的結果,觸發下一個promise相應的狀態 ret.then(function(value){ resolve(value); },function(reason){ reject(reason); }); }else{ resolve(ret); } } function errback(reason){ reason = isFunction(onRejected) && onRejected(reason) || reason; reject(reason); } if(promise._status === PENDING){ promise._resolves.push(callback); promise._rejects.push(errback); }else if(promise._status === FULFILLED){ // 狀態改變後的then操做,馬上執行 callback(promise._value); }else if(promise._status === REJECTED){ errback(promise._reason); } }); }
這裏說明下
var isThenable = function(obj){
return obj && typeof obj['then'] == 'function';
}
也就是說返回的對象帶有then方法,咱們就看成promise對象
到這裏咱們主要的工做就完成了,其餘的all,race等方法都很簡單,具體能夠到這裏看完整的實現
https://github.com/ygm125/promise/blob/master/promise.js
下面咱們來作幾個例子來看下效果
var getData100 = function(){ return Promise(function(resolve,reject){ setTimeout(function(){ resolve('100ms'); },100); }); } var getData200 = function(){ return Promise(function(resolve,reject){ setTimeout(function(){ resolve('200ms'); },200); }); } getData100().then(function(data){ console.log(data); // 100ms return getData200(); }).then(function(data){ console.log(data); // 200ms return data + data; }).then(function(data){ console.log(data) // 200ms200ms });
固然能夠直接getData100().then(getData200).then(function(val){})
then能夠只傳一個,接受成功的回調,也能夠用catch方法,接受失敗的回調,
catch是then的一個語法糖,至關於promise.then(undefined, onRejected)
也能夠用all來並行執行
Promise.all([getData100(),getData200()]).then(function(value){ console.log(value) // ['100ms','200ms'] });
結果的順序與傳入的順序相同。
咱們也能夠直接建立一個以obj爲值的成功狀態的promise,
Promise.resolve('FULFILLED').then(function(val){ console.log(val) // FULFILLED });
實現都至關簡單,看代碼就懂。
這裏也能夠作一些好玩的,好比建立一個delay方法
Promise.prototype.delay = function(ms){ return this.then(function(val){ return Promise.delay(ms,val); }) } Promise.delay = function(ms,val){ return Promise(function(resolve,reject){ setTimeout(function(){ resolve(val); },ms); }) }
咱們能夠每隔多少毫秒執行一些操做
Promise.delay(1000).then(function(){ // 一些操做 }).delay(1000).then(function(){ // 一些操做 })
咱們也能夠包裝一個循環,執行多少次,每次延遲多少秒執行什麼操做
var len = 0, words = '你好,你是誰?'; function count(num,ms,cb){ var pro = Promise.resolve(); for (var i = 0; i < num; i++) { pro = pro.delay(ms).then(function(v){ return cb(v); }); }; } count(words.length,800,function(){ var w = words.substr(0,++len); console.log(w); })
更多的東西等你來實現~