1. Promise的狀態
Promise對象有三個狀態:
1. 進行中(pending)
2. 成功(resolved)
3. 失敗(rejected)
2. 生成一個Promise對象
1. 構造函數
new Promise(function(resolve,reject){ });
resolve和reject函數是瀏覽器內部實現的,直接調用即可。
2. Promise.resolve
Promise.resolve()直接返回一個resolve狀態的Promise對象
Promise.resolve可以用來生成一個then鏈
3. Promise.reject
Promise.reject()直接返回一個reject狀態的Promise對象
3. Promise的then的用法
Promise的then永遠返回一個新的Promise,Promise的catch是then(null,rejection)的語法糖,catch中也會返回一個新的Promise。
建議在Promise的then永遠return或throw,不要只是執行一個函數。
例如:
var aPromise = new Promise(function (resolve) { resolve(100); }); var thenPromise = aPromise.then(function (value) { console.log(value); }); var catchPromise = thenPromise.catch(function (error) { console.error(error); }); console.log(aPromise !== thenPromise); // => true console.log(thenPromise !== catchPromise);// => true
=== 是嚴格相等比較運算符,我們可以看出這三個對象都是互不相同的,這也就證明了 then 和 catch 都返回了和調用者不同的promise對象。
1. Promise的then內部可以做三種事情:
(1). return 另一個promise
(2). return 一個同步值(或者undefined)
因為javascript函數無返回值時候,默認返回undefined,所以只是執行一個函數,不return,默認就是返回undefined。
返回一個同步值在Promise中會將同步代碼包裹為promise,得到的還是一個promsie。返回一個同步值是有用處的,例如,
一個異步值在內存中做了緩存,可以直接從內存中拿到該值,直接返回,不必再調用異步接口。
getUserByName('xxx').then(function(user){
if(imMemoryCache[user.id]){
return inMemoryCache[user.id];
}
return getUserAccountById(user.id);
}).then(function(userAccount){
});
(3). throw 一個同步異常
2. Promise的一些寫法
new Promise(function(resolve,reject){ resolve(syncValue); }).then(/*...*/) //可以寫成 Promise.resolve(syncValue).then(/*...*/) //一個錯誤也可以寫成 Promise.reject(new Error('...'))
這樣無論成功或失敗都可以后面的then和catch中捕獲和繼續操作
3. Promise的then中只能傳遞函數,如果為其他類型,例如另一Promise,會被解釋為null,此時Promsie的值傳遞會穿透
例如:
Promise.resolve('foo').then(Promise.resolve('bar')).then(function(result){
console.log(result);
});
//會被解釋為:
Promise.resolve('foo').then(null).then(function(result){
console.log(result);
});
第一個resolve的值會穿透到then,打印出foo。
4. then的四種寫法的區別
// 寫法一 f1().then(function () { return f2(); }); // 寫法二 f1().then(function () { f2(); }); // 寫法三 f1().then(f2()); // 寫法四 f1().then(f2);
1. 寫法1和4完全等價,f1值能傳遞到f2,f2的返回值也能繼續向后面的then傳遞
2. 寫法2相當於默認return undefined,無法向后面的then傳遞值
3. 寫法3能夠向后面傳遞f2的值,沒有更深刻的解釋(有懂的朋友請評論告知)
4. Promise的調用方法
每個then返回一個新的promise調用,這種寫法被稱為composing promises。
promise1.then(function(){ return promise2; }).then(function(){ return promise3; }).then(function(){ return promise4; }).catch(function(err){ console.log(err); });
5. Promise的並行執行
由於promise一旦被創建,就會立即執行,所以拿到一個Promise數組時候,其中的promise必然全部開始執行了。
因此要讓一系列promise順序執行,只能將promise放在一個函數中,在要執行的時候才去創建他,就是一個工廠
函數,promiseFactory。promise並行執行的代碼應該如下:
function executeSequentially(promiseFactories){ var res = Promsie.resolve(); promiseFactories.forEach(function(promiseFactory){ res = res.then(promiseFactory); }); return res; } //工廠函數只是簡單的創建一個promise function promiseFactory(){ return createAPromise(); }
6. Promise捕獲錯誤
7. 實現一個Promise版本的ajax
//原生版本 function Http(){ } Http.prototype = { get:function(opts){ return this.ajax(opts); }, post:function(){ return this.ajax(opts); }, ajax:function(opts){ return Promise(function(resolve,reject){ var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('...'); var {url,method,data,async,success,fail} = options; var sendBody = null; var qs = Object.keys(data).reduce(function(cur,pre,index){ return pre + '&' + encodeURIComponent(cur) + '=' + encodeURIComponent(data[cur]); },'').slice(1); if(medthod == 'get'){ url += '?' + qs; } else if(medhot == 'post'){ xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); sendBody = qs || null; } xhr.onreadystatechange = function(){ if(xhr.readystate == 4){ if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){ resolve(xhr,xhr.responseText); } } else{ reject(xhr,xhr.responseText); } } xhr.open(method,url,async); xhr.send(sendBody); }); } } //jquery版本 function Http(){ } Http.prototype = { get:function(opts){ return this.ajax(opts); }, post:function(opts){ return this.ajax(opts); }, ajax:function(){ return $.ajax(opts); } }
參考:https://juejin.im/entry/596f2ab2f265da6c25190f41
http://javascript.ruanyifeng.com/advanced/promise.html#toc2
https://www.kancloud.cn/kancloud/promises-book/44256
