消費(fèi)者怎么看待 then, catch, finally
消費(fèi)者:then,catch,finally
昨天講了關(guān)于 Promise 的理解,有人在下面評(píng)論說要我出關(guān)于源碼的解析,能力有限只能循序漸進(jìn)了,我們還是先把基礎(chǔ)的搞明白,再逐步深入。

Promise對(duì)象充當(dāng)執(zhí)行者(“產(chǎn)生代碼”或“singer”)和消費(fèi)函數(shù)(“fans”)之間的鏈接,它們將接收結(jié)果或錯(cuò)誤。使用.then、.catch和.finally方法可以注冊(cè)(訂閱)消費(fèi)函數(shù)。
then
最重要,最基本的是 then 。
他的的語(yǔ)法是:
promise.then(
??function(result)?{?/*?handle?a?successful?result?*/?},
??function(error)?{?/*?handle?an?error?*/?}
);
then的第一個(gè)參數(shù)是一個(gè)函數(shù),它在promise被解析時(shí)運(yùn)行,并接收結(jié)果。
then的第二個(gè)參數(shù)是一個(gè)函數(shù),當(dāng)promise被拒絕時(shí)運(yùn)行,并接收錯(cuò)誤。
例如,以下是人們對(duì)成功解決的反應(yīng):
let?promise?=?new?Promise(function(resolve,?reject)?{
??setTimeout(()?=>?resolve("done!"),?1000);
});
//?resolve?runs?the?first?function?in?.then
promise.then(
??result?=>?alert(result),?//?shows?"done!"?after?1?second
??error?=>?alert(error)?//?doesn't?run
);
執(zhí)行了第一個(gè)函數(shù)。
在被拒絕的情況下,第二個(gè)
let?promise?=?new?Promise(function(resolve,?reject)?{
??setTimeout(()?=>?reject(new?Error("Whoops!")),?1000);
});
//?reject?runs?the?second?function?in?.then
promise.then(
??result?=>?alert(result),?//?doesn't?run
??error?=>?alert(error)?//?shows?"Error:?Whoops!"?after?1?second
);
如果我們只對(duì)成功完成感興趣,那么我們只能為.then提供一個(gè)函數(shù)參數(shù):
let?promise?=?new?Promise(resolve?=>?{
??setTimeout(()?=>?resolve("done!"),?1000);
});
promise.then(alert);?//?shows?"done!"?after?1?second
catch
如果我們只對(duì)錯(cuò)誤感興趣,那么可以使用null作為第一個(gè)參數(shù):.then(null, errorHandlingFunction)。或者我們可以使用.catch(errorHandlingFunction),兩者完全相同:
let?promise?=?new?Promise((resolve,?reject)?=>?{
??setTimeout(()?=>?reject(new?Error("Whoops!")),?1000);
});
//?.catch(f)?is?the?same?as?promise.then(null,?f)
promise.catch(alert);?//?shows?"Error:?Whoops!"?after?1?second
調(diào)用.catch(f)完全是對(duì).then(null, f)的模擬,它只是一個(gè)簡(jiǎn)寫。
finally
就像在一個(gè)普通的try{…} catch{…}終于有了承諾。
調(diào)用.finally(f)類似于.then(f, f),因?yàn)閒總是在promise被解決時(shí)運(yùn)行:無(wú)論是resolve還是reject。
finally是一個(gè)很好的處理程序,用于執(zhí)行清理,例如停止我們的加載指示器,因?yàn)樗鼈儾辉傩枰?,無(wú)論結(jié)果是什么。
是這樣的:
new?Promise((resolve,?reject)?=>?{
??/*?do?something?that?takes?time,?and?then?call?resolve/reject?*/
})
??//?runs?when?the?promise?is?settled,?doesn't?matter?successfully?or?not
??.finally(()?=>?stop?loading?indicator)
??//?so?the?loading?indicator?is?always?stopped?before?we?process?the?result/error
??.then(result?=>?show?result,?err?=>?show?error)
也就是說,finally(f)并不是then(f,f)的別名。有一些細(xì)微的區(qū)別:
finally處理程序沒有參數(shù)。在最后,我們不知道諾言是否成功。沒關(guān)系,因?yàn)槲覀兊娜蝿?wù)通常是執(zhí)行“一般的”收尾過程。
finally處理程序?qū)⒔Y(jié)果和錯(cuò)誤傳遞給下一個(gè)處理程序。
例如,這里的結(jié)果被傳遞給finally:
new?Promise((resolve,?reject)?=>?{
??setTimeout(()?=>?resolve("result"),?2000)
})
??.finally(()?=>?alert("Promise?ready"))
??.then(result?=>?alert(result));?//?<--?.then?handles?the?result
在promise中有一個(gè)錯(cuò)誤,最后傳遞給catch:
new?Promise((resolve,?reject)?=>?{
??throw?new?Error("error");
})
??.finally(()?=>?alert("Promise?ready"))
??.catch(err?=>?alert(err));??//?<--?.catch?handles?the?error?object
例子:loadScript
我們?cè)谇耙徽轮惺褂昧薼oadScript函數(shù)來加載腳本。
下面是基于回調(diào)的變體,只是為了提醒我們:
function?loadScript(src,?callback)?{
??let?script?=?document.createElement('script');
??script.src?=?src;
??script.onload?=?()?=>?callback(null,?script);
??script.onerror?=?()?=>?callback(new?Error(`Script?load?error?for?${src}`));
??document.head.append(script);
}
我們用 Promise 重寫一下。
新的函數(shù)loadScript不需要回調(diào)。相反,它將創(chuàng)建并返回一個(gè)Promise對(duì)象,該對(duì)象將在加載完成時(shí)解析。外部代碼可以使用.then向其添加處理程序(訂閱函數(shù)):
function?loadScript(src)?{
??return?new?Promise(function(resolve,?reject)?{
????let?script?=?document.createElement('script');
????script.src?=?src;
????script.onload?=?()?=>?resolve(script);
????script.onerror?=?()?=>?reject(new?Error(`Script?load?error?for?${src}`));
????document.head.append(script);
??});
}
用法
let?promise?=?loadScript("https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js");
promise.then(
??script?=>?alert(`${script.src}?is?loaded!`),
??error?=>?alert(`Error:?${error.message}`)
);
promise.then(script?=>?alert('Another?handler...'));
