相信之前用過JavaScript的朋友都碰到過異步回調(diào)地獄(callback hell),N多個回調(diào)的嵌套不僅讓代碼讀起來十分困難,維護(hù)起來也很不方便。
其實C#在Task出現(xiàn)之前也是有類似場景的,Async Programming Mode時代,用Action和Func做回調(diào)也很流行,不過也是意識到太多的回調(diào)嵌套代碼可讀性差且維護(hù)不易,微軟引入了Task和Task-based Async Pattern。
雖然不知道是哪個語言最早有這個概念,但相信是C#把async await帶到流行語言的舞臺,接著其他語言也以不同的形式支持async await,如Python, Dart, Swift等。
JavaScript同樣在ES6開始支持Promise和Generator,并在ES7中提出支持async await的議案。

成都創(chuàng)新互聯(lián)公司專業(yè)為企業(yè)提供青龍網(wǎng)站建設(shè)、青龍做網(wǎng)站、青龍網(wǎng)站設(shè)計、青龍網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計與制作、青龍企業(yè)網(wǎng)站模板建站服務(wù),十余年青龍做網(wǎng)站經(jīng)驗,不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡(luò)服務(wù)。
這篇先來看看Promise:
Promise之于TypeScript,相當(dāng)于Task之于C#,只有返回Promise的函數(shù)才能使用async await。Promise其實就是一個可以獲取異步結(jié)果,并封裝了一些異步操作的對象。
有三個狀態(tài):pending: 進(jìn)行中resolved: 成功rejected: 失敗
并且這三個狀態(tài)只有兩種轉(zhuǎn)換:pending->resolved、pending->rejected,不是成功就是失敗,并沒有多余的狀態(tài)轉(zhuǎn)換。
這兩種轉(zhuǎn)換都是由異步返回的結(jié)果給定的,成功取回數(shù)據(jù)就是resolved,取數(shù)據(jù)出異常就是rejected。
也因此,這轉(zhuǎn)換過后的結(jié)果就是固定的了,不可能在轉(zhuǎn)換過后還會變回pending或其他狀態(tài)。Promise不能在任務(wù)進(jìn)行中取消,只能等結(jié)果返回,這點上不如C#的Task,Task可以通過CancelTaskToken來取消任務(wù)。
可以直接new一個Promise對象,構(gòu)造函數(shù)的參數(shù)是一個有兩個參數(shù)的函數(shù)。
這兩個參數(shù)一個是resove,用來在異步操作成功后調(diào)用,并把異步結(jié)果傳出去,調(diào)用resove后狀態(tài)就由pending->resolved。
另一個是reject,用來在失敗或異常時調(diào)用,并把錯誤消息傳出去,調(diào)用reject后狀態(tài)由pending->rejected。
var promise = new Promise(function(resolve, reject) {
});通常需要在成功或失敗后做一些操作,這時需要then來做這個事,then可以有兩個函數(shù)參數(shù),第一個是成功后調(diào)用的,第二個是失敗調(diào)用的,第二個是可選的。
另外,then返回的也是一個Promise,不過不是原來的那個,而是新new出來的,這樣可以鏈?zhǔn)秸{(diào)用,then后面再接then。
// 函數(shù)參數(shù)用lambda表達(dá)式寫更簡潔promise.then(success => { console.info(success);
}, error => { console.info(error);
}).then(()=>console.info('finish'));在實際場景中,我們可能需要在一個異步操作后再接個異步操作,這樣就會有Promise的嵌套操作。
下面的代碼顯示的是Promise的嵌套操作:p1先打印"start",延時兩秒打印"p1"。p2在p1完成后延時兩秒打印"p2"。
function delay(): Promise<void>{ return new Promise<void>((resolve, reject)=>{setTimeout(()=>resolve(), 2000)});
}let p1 = new Promise((resolve, reject) => { console.info('start');
delay().then(()=>{ console.info('p1');
resolve()
});
});let p2 = new Promise((resolve, reject) => {
p1.then(()=>delay().then(()=>resolve()));
});
p2.then(()=>console.info('p2'));上面提到Promise出錯時把狀態(tài)變?yōu)?code>rejected并把錯誤消息傳給reject函數(shù),在then里面調(diào)用reject函數(shù)就可以顯示異常。
不過這樣寫顯得不是很友好,Promise還有個catch函數(shù)專門用來處理錯誤異常。
而且Promise的異常是冒泡傳遞的,最后面寫一個catch就可以捕獲到前面所有promise可能發(fā)生的異常,如果用reject就需要每個都寫。
所以reject函數(shù)一般就不需要在then里面寫,在后面跟個catch就可以了。
new Promise(function(resolve, reject) { throw new Error('error');
}).catch(function(error) { console.info(error); // Error: error});也如上面所說狀態(tài)只有兩種變化且一旦變化就固定下來,所以如果已經(jīng)在Promise里執(zhí)行了resolve,再throw異常是沒用的,catch不到,因為狀態(tài)已經(jīng)變成resolved。
new Promise(function(resolve, reject) {
resolve('success'); throw new Error('error');
}).catch(function(error) { console.info(error); // 不會執(zhí)行到這里});另外,catch里的代碼也可能出異常,所以catch后面也還可以跟catch的議案。
new Promise(function(resolve, reject) { throw new Error('error');
}).catch(function(error) { console.info(error); // Error: error
throw new Error('catch error');
}).catch(function(error){ console.info(error); // Error: catch error };異常的try...catch后面可以跟finally來執(zhí)行必須要執(zhí)行的代碼,Promise原生并不支持,可以引入BlueBird的擴(kuò)展庫來支持。
另外還有done在最后面來表示執(zhí)行結(jié)束并拋出可能出現(xiàn)的異常,比如最后一個catch代碼塊里的異常。
let p = new Promise(function(resolve, reject) {
x = 2; // error, 沒有聲明x變量
resolve('success');
}).catch(function(error) { console.info(error);
}).finally(()=>{ // 總會執(zhí)行這里
console.info('finish');
y = 2; // error, 沒有聲明y變量}).done();
try{
p.then(()=>console.info('done'));
} catch (e){ console.info(e); // 由于最后面的done,所以會把finally里的異常拋出來,如果沒有done則不會執(zhí)行到這里}雖然JavaScript是單線程語言,但并不妨礙它執(zhí)行一些IO并行操作,如不阻塞發(fā)出http request,然后異步等待。Promise除了用then來順序執(zhí)行外,也同樣可以不阻塞同時執(zhí)行多個Promise然后等所有結(jié)果返回再進(jìn)行后續(xù)操作。
C#的Task有個WhenAll的靜態(tài)方法來做這個事,Promise則是用all方法達(dá)到同樣目的。all方法接受實現(xiàn)Iterator接口的對象,比如數(shù)組。
let p = Promise.all([p1, p2, p3]);
all返回的是一個新的Promise- p,p的狀態(tài)是由p1, p2, p3同時決定的:
p.resolved = p1.resolve && p2.resolve && p3.resolve p.rejected = p1.rejected || p2.rejected || p3.rejected
也就是說p的成功需要p1,p2,p3都成功,而只要p1, p2, p3里有任何一個失敗則p失敗并退出。
Promise還有一個方法race同樣是并行執(zhí)行多個Promise,不同于all的是它的成功狀態(tài)和錯誤狀態(tài)一樣,只要有一個成功就成功,如同C# Task的Any方法。
名稱欄目:從C#到TypeScript-Promise
URL標(biāo)題:http://www.chinadenli.net/article4/gspeoe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站制作、外貿(mào)網(wǎng)站建設(shè)、App設(shè)計、網(wǎng)頁設(shè)計公司、建站公司、網(wǎng)站內(nèi)鏈
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)