以下是第四課的翻譯內(nèi)容
Javascript Promise
這節(jié)課準(zhǔn)備聊Javascript Promise
燕偶,如上節(jié)課所看到的情況,要維護(hù)大量異步回調(diào)可能相當(dāng)棘手,可能會(huì)導(dǎo)致代碼混亂,起碼會(huì)讓你感到頭疼。
馬上介紹Javascript Promise
渴逻,讓我們能更容易去組織維護(hù)這類回調(diào)方法。
究竟什么是 Promise音诫? Promise 是一個(gè)對(duì)象惨奕,代表一種暫時(shí)還沒完成但將來某個(gè)時(shí)間點(diǎn)會(huì)處理的動(dòng)作
,本質(zhì)上是一種占位符纽竣,例如 HTTP 請(qǐng)求等異步操作的結(jié)果墓贿。
例如我們發(fā)起 http 請(qǐng)求數(shù)據(jù),一旦發(fā)出異步請(qǐng)求蜓氨,它就會(huì)在數(shù)據(jù)被獲取并返回之前先返回 Promise 對(duì)象給我們聋袋。有了 Promise 對(duì)象就可以注冊(cè)回調(diào)函數(shù)
,當(dāng)請(qǐng)求完成就會(huì)執(zhí)行這些注冊(cè)的回調(diào)函數(shù)穴吹。
Promise 是比較新的功能幽勒,我們可以通過最新版本 ES6
進(jìn)行使用。然而還有不少如 Q
之類的庫(kù)實(shí)現(xiàn)了 Promise港令。
下面我準(zhǔn)備用瀏覽器原生支持的 Promise 庫(kù)啥容,通過 can I use 要查看瀏覽器支持,主要 IE 系列不支持顷霹。
我會(huì)選擇支持 ES6 Promise API 的 chrome咪惠,如果需要發(fā)布代碼,建議還是使用如 Q
的 Promise 庫(kù)淋淀,保證全瀏覽器支持遥昧,Q 的使用可以在 github 上查找。
目錄結(jié)構(gòu)
-- data
????|_ tweet.json
????|_ friend.json
????|_ video.json
-- async.js
-- index.html
開始創(chuàng)建一個(gè)簡(jiǎn)單的 Promise朵纷,首先注意到的是這個(gè)看起來有點(diǎn)嚇人的 get
函數(shù)炭臭,實(shí)際是一個(gè)通過 Ajax 獲取數(shù)據(jù)的方法。
'async.js'
function get(url) {
return new Promise(function (resolve, reject) {
var http = new XMLHttpRequest();
http.open('get', url, true);
http.onload = function () {
if (http.status === 200) {
resolve(JSON.parse(http.response));
} else {
resolve(http.statusText);
}
};
http.onerror = function () {
resolve(http.statusText);
};
http.send();
});
}
將 get 函數(shù)返回的 Promise 對(duì)象賦給變量 promise袍辞,數(shù)據(jù)返回之前 Promise 對(duì)象已賦值給 promise鞋仍,之前所說的 Promise 是一個(gè)可以讓我們注冊(cè)回調(diào)函數(shù)的占位符對(duì)象
,當(dāng)變成已完成狀態(tài)并且數(shù)據(jù)返回正常的時(shí)候搅吁,可以使用 then
方法威创,而 catch
方法則是用來捕獲錯(cuò)誤落午。下面的例子采用了鏈?zhǔn)綄懛?/code>。
'async'
var promise = get('data/tweet.json'); // promise 是一個(gè)將來會(huì)發(fā)生事情的占位符那婉,
promise.then(function (tweet) { // 狀態(tài) OK 后執(zhí)行 then 里的回調(diào)函數(shù)
console.log(tweet);
}).then(function (friend) {
console.log(friend);
}).then(function (video) {
console.log(video);
}).catch(function (error) {
console.log(error);
});
你可能會(huì)想為什么這種寫法比常規(guī)的回調(diào)函數(shù)好板甘,因?yàn)?then 和 catch 里的畢竟還是回調(diào)函數(shù)党瓮,實(shí)際上更好的是當(dāng)我們需要寫多個(gè)異步請(qǐng)求我們可以以鏈?zhǔn)綄懛▉磉B接這幾個(gè)異步請(qǐng)求
详炬。
'async'
promise.then(function (tweet) {
console.log(tweet);
return get('data/friend.json'); // return 的內(nèi)容將會(huì)以下一個(gè) then 回調(diào)函數(shù)中的參數(shù)出現(xiàn)
}).then(function (friend) {
console.log(friend);
return get('data/video.json');
}).then(function (video) {
console.log(video);
}).catch(function (error) {
console.log(error);
});
這種寫法比起嵌套回調(diào)函數(shù)看起來好多了,是更優(yōu)雅的處理回調(diào)函數(shù)的方式寞奸。
了解 Promise
下面來了解 get 方法究竟在做什么:
- get 方法的 url 參數(shù)是我們需要請(qǐng)求數(shù)據(jù)的 url
- 返回一個(gè) Promise 對(duì)象
- Promise 對(duì)象有 resolve 和 reject 函數(shù)
- resolve 是成功時(shí)候會(huì)執(zhí)行的函數(shù)呛谜,函數(shù)的參數(shù)會(huì)返回到
then
的回調(diào)函數(shù)的參數(shù) - reject 是失敗時(shí)候會(huì)執(zhí)行的函數(shù),函數(shù)的參數(shù)會(huì)返回到
catch
的回調(diào)函數(shù)的參數(shù)
- resolve 是成功時(shí)候會(huì)執(zhí)行的函數(shù)呛谜,函數(shù)的參數(shù)會(huì)返回到
- 在 Promise 的回調(diào)函數(shù)體里枪萄,是第一節(jié)課創(chuàng)建 ajax 請(qǐng)求的代碼
以上就是創(chuàng)建 Promise 的過程隐岛。
'async.js'
function get(url) {
return new Promise(function (resolve, reject) {
var http = new XMLHttpRequest();
http.open('get', url, true);
http.onload = function () { // 如果瀏覽器支持 Promise 也會(huì)支持 onloady 與 onerror 方法
if (http.status === 200) {
resolve(JSON.parse(http.response)); // 當(dāng)狀態(tài)碼 200,執(zhí)行 resolve 方法瓷翻,返回響應(yīng)內(nèi)容
} else { // 否則執(zhí)行 reject 方法聚凹,返回錯(cuò)誤信息
reject(http.statusText);
}
};
http.onerror = function () { // 出其他錯(cuò)誤同樣執(zhí)行 reject 方法,返回錯(cuò)誤信息
reject(http.statusText);
};
http.send();
});
}
jQuery 的 Promise
實(shí)際上如今的 jQuery 也實(shí)現(xiàn)了 Promise齐帚,上面例子主要是介紹 Promise 的背景與內(nèi)里的工作原理妒牙,便于學(xué)習(xí)理解。
利用 jQuery 的 Promise 特性發(fā)起多個(gè)請(qǐng)求:
'async.js'
$.get('data/tweet.json').then(function(tweet){
console.log(tweet);
return $.get('data/friend.json');
}).then(function (friend) {
console.log(friend);
return $.get('data/video.json');
}).then(function (video) {
console.log(video);
}).catch(function (error) {
console.log(error);
});
跟上節(jié)課的 $.get 使用回調(diào)方式發(fā)起三次請(qǐng)求對(duì)比对妄,看起來更容易維護(hù)與整潔(抽象了回調(diào)函數(shù)的代碼)湘今,有點(diǎn)像同步代碼。