
Promise介紹
Promise 是 JavaScript 的異步操作解決方案,是ES6提出的異步操作解決方案之一。
其為異步操作提供統(tǒng)一接口。它起到代理作用(proxy),充當(dāng)異步操作與回調(diào)函數(shù)之間的中介,使得異步操作具備同步操作的接口。Promise 可以讓異步操作寫起來,就像在寫同步操作的流程,而不必一層層地嵌套回調(diào)函數(shù)。
為什么會有promise?
其實在jquery很早以前就有了十分類似promise的方案,該方案的出現(xiàn)是為了解決回調(diào)地獄以及傳統(tǒng)回調(diào)寫法不太符合開放封閉的設(shè)計原則而產(chǎn)生的,Promise的出現(xiàn)很好地實現(xiàn)了對擴(kuò)展開放,對修改封閉的原則,可拓展性和可讀性較高。
傳統(tǒng)的回調(diào)寫法
step1(function (value1) {
step2(value1, function(value2) {
step3(value2, function(value3) {
step4(value3, function(value4) {
// ...
});
});
});
});
jQuery異步操作歷史
jQuery 1.5版本之前
提出的異步解決方案,以ajax為主:
var ajax = $.ajax({
url: './data.json',
success: function () {
console.log('success 1')
console.log('success 2')
console.log('success 3')
},
error: function () {
console.log('error')
}
})
console.log(ajax) //返回的是一個XHR對象
jQuery 1.5版本
引入deferred對象,deferred英文是延期的意思
var ajax = $.ajax('./data.json')
ajax.done(function () {
console.log('success a')
}).fail(function () {
console.log('fail 1')
}).done(function () {
console.log('success b')
}).fail(function () {
console.log('fail 2')
}).done(function () {
console.log('success c')
}).fail(function () {
console.log('fail 3')
})
console.log(ajax) //返回一個deferred對象
jQuery 1.5版本之后
使用了then關(guān)鍵字,此時,我們可以看到,已經(jīng)和Promise的寫法很像了。
var ajax = $.ajax('./data.json')
ajax.then(function () {
console.log('success 100')
}, function () {
console.log('fail 100')
}).then(function () {
console.log('success 200')
}, function () {
console.log('fail 200')
}).then(function () {
console.log('success 300')
}, function () {
conso3le.log('fail 00')
})
jQuery Deferred的使用
首先,我們看下未使用deferred的情況
var wait = function () {
var task = function () {
console.log('執(zhí)行完成')
}
setTimeout(task, 2000)
}
wait()
引入deferred后可以使用promise的寫法,傳入dtd, 成功執(zhí)行resolve, 失敗執(zhí)行reject
function waitHandle() {
// 定義
var dtd = $.Deferred() // 創(chuàng)建一個deferred對象
var wait = function (dtd) {
var task = function () {
console.log('執(zhí)行完成')
// 成功
dtd.resolve()
// 失敗
// dtd.reject()
}
setTimeout(task, 1000)
// wait 返回
// return dtd 1.5之前返回deferred對象
return dtd.promise() // 1.5之后返回promise
}
// 最終返回
return wait(dtd)
}
deferred的實際使用及API分類
API分類
第一類:dtd.resolve, dtd.reject
第二類:dtd.then, dtd.done, dtd.fail
兩者不能混用, then是被動監(jiān)聽執(zhí)行,resolve等是主動執(zhí)行
var w = waitHandle() // promise 對象
//以下是1.5之前的寫法,返回的是deferred對象
/*w.then(function () {
console.log('ok 1')
}, function () {
console.log('err 1')
})
*/
//以下是1.5之后的jquery promise寫法,使用者不能直接使用主動調(diào)用的w.reject, w.resolve方法
$.when(w).then(function () {
console.log('ok 1')
}, function () {
console.log('err 1')
})
Promise
Promise標(biāo)準(zhǔn)
promise可以看作一種狀態(tài)管理
- 總共有三種狀態(tài) pending, fulfilled, rejected
- 初始狀態(tài)是pending
- pending可以變?yōu)閒ulfilled或pending之一
- 狀態(tài)變化不可逆
promise必須實現(xiàn)then方法
- then()必須可以接收兩個函數(shù)作為參數(shù)
- then()返回的必須是一個promise實例
then 方法可以接受兩個回調(diào)函數(shù),第一個是異步操作成功時(變?yōu)閒ulfilled狀態(tài))時的回調(diào)函數(shù),第二個是異步操作失?。ㄗ?yōu)閞ejected)時的回調(diào)函數(shù)(該參數(shù)可以省略)。一旦狀態(tài)改變,就調(diào)用相應(yīng)的回調(diào)函數(shù)。then對上一步的結(jié)果負(fù)責(zé),then中的resolve在上一步resolve和reject都成功時執(zhí)行,reject在上一步resolve和reject任意一個失敗時執(zhí)行,可以進(jìn)行鏈?zhǔn)秸{(diào)用
Promise解決了什么問題?
使用Promise其實并沒有改變JS異步和單線程的本質(zhì),只是從寫法上杜絕了callback這種形式。Promise是一種語法糖,其解構(gòu)了代碼,更好地符合了開放封閉原則。
一般現(xiàn)代瀏覽器都支持了Promise,若不支持可以使用bluebird插件
Promise的寫法
function loadImg(src) {
var promise = new Promise(function (resolve, reject) {
var img = document.createElement('img')
img.onload = function () {
resolve(img)
}
img.onerror = function () {
reject('圖片加載失敗')
}
img.src = src
})
return promise
}
Promise的異常捕獲
promise.then最后加上.catch,可以統(tǒng)一捕獲throw的系統(tǒng)錯誤以及reject中的信息
var result = loadImg(src)
result.then(function (img) {
console.log(1, img.width)
return img
}).then(function (img) {
console.log(2, img.height)
}).catch(function (ex) {
// 統(tǒng)一捕獲異常
console.log(ex)
})
Promise其他api, all與race
all需要傳入多個promise實例,全部實例完成后再繼續(xù),而race只需其中一個完成即可繼續(xù)

async await
promise中的then只是將callback進(jìn)行了拆分。
更進(jìn)一步可以使用asyn 結(jié)合await使用同步的方式寫異步的callback. 其是對promise的進(jìn)一步封裝,對寫法上的封裝。改變不了JS單線程、異步的本質(zhì)
- 使用方法
在return promise對象的函數(shù)前加await
可以獲取promise執(zhí)行后的結(jié)果,而不是返回promise對象
const load = async function() {
const result1 = await loadImg(src1)
console.log(result1)
const result2 = await loadImg(src2)
console.log(result2)