




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
?今天,我們創(chuàng)建自己的JavaScriptPromise實(shí)現(xiàn)[FromScratch]。要?jiǎng)?chuàng)建一個(gè)新的承諾,我們只需newPromise像這樣使用:
newPromise((resolve,reject)=>{
...
resolve(someValue)
})我們傳遞一個(gè)定義Promise特定行為的回調(diào)。Promise是一個(gè)容器:為我們提供API來管理和轉(zhuǎn)換價(jià)值這讓我們能夠管理和轉(zhuǎn)變實(shí)際上尚不存在的價(jià)值。使用容器來包裝值是函數(shù)式編程范例中的常見做法。函數(shù)式編程中有不同種類的“容器”。最著名的是函子和單子。實(shí)施承諾以了解其內(nèi)部結(jié)構(gòu)1、then()方法classPromise{
constructor(then)
{
this.then=then
}}constgetItems=newPromise((resolve,reject)=>{
HTTP.get('/items',(err,body)=>{
if(err)returnreject(err)
resolve(body)
})})getItems.then(renderItems,console.error)非常簡(jiǎn)單,到目前為止,這個(gè)實(shí)現(xiàn)除了具有success(
resolve)和error(
reject)回調(diào)的任何函數(shù)之外,沒有做任何其他事情。因此,檢查一下,當(dāng)我們從頭開始做出承諾時(shí),我們有一個(gè)額外的(通常不公開的)步驟需要實(shí)施。2.映射目前,我們的Promise實(shí)現(xiàn)無法正常工作-它過于簡(jiǎn)化,并且不包含正常工作所需的所有行為。我們的實(shí)現(xiàn)目前缺少什么功能和/或行為之一?首先,我們無法鏈?zhǔn)?then()調(diào)用。Promise可以鏈接多個(gè).then()方法,并且每次.then()解析其中任何語句的結(jié)果時(shí)都應(yīng)返回一個(gè)新的Promise。這是讓Promise如此強(qiáng)大的主要功能之一。它們幫助我們逃離回調(diào)地獄。這也是我們目前尚未實(shí)現(xiàn)的Promise實(shí)現(xiàn)的一部分。在我們的實(shí)現(xiàn)中,結(jié)合使Promise鏈正常工作所需的所有功能可能會(huì)有點(diǎn)混亂-但我們得到了這一點(diǎn)。讓我們深入研究、簡(jiǎn)化并設(shè)置JavaScriptPromise的實(shí)現(xiàn),以始終從語句返回或解析其他Promise
.then()。首先,我們需要一個(gè)方法來轉(zhuǎn)換Promise包含的值并返回一個(gè)新的Promise。嗯,這聽起來是不是很奇怪?讓我們仔細(xì)看看。啊哈,這聽起來和Atotype.map實(shí)現(xiàn)方式完全一樣,不是嗎?.map的類型簽名是:map::(a->b)->Arraya->Arrayb簡(jiǎn)單來說,這意味著map接受一個(gè)函數(shù)并將type轉(zhuǎn)換a為type
b。這可以是一個(gè)String到Boolean,然后它將采用a
(字符串)的數(shù)組并返回b
(布爾)的數(shù)組。我們可以構(gòu)建一個(gè)Ptotype.map具有非常相似簽名的函數(shù),該函數(shù)Atotype.map允許我們將已解決的Promise結(jié)果映射到另一個(gè)正在進(jìn)行的Promise。這就是我們能夠鏈接.then's具有返回任何隨機(jī)結(jié)果的回調(diào)函數(shù)的方式,但隨后似乎神奇地以某種方式返回Promise,而無需我們實(shí)例化任何新的Promise。map::(a->b)->Promisea->Promiseb以下是我們?nèi)绾卧谀缓髮?shí)現(xiàn)這一魔法:classPromise{
constructor(then)
{
this.then=then
}
map(mapper)
{
returnnewPromise(
(resolve,reject)=>
this.then(x=>resolve(mapper(x)),
reject
)
)
}}我們剛才做了什么?讓我們來分解一下。當(dāng)我們創(chuàng)建或?qū)嵗疨romise時(shí),我們定義了一個(gè)回調(diào),它是我們成功解析結(jié)果時(shí)使用的then回調(diào)。我們創(chuàng)建一個(gè)接受映射器函數(shù)的映射函數(shù)。這個(gè)映射函數(shù)返回一個(gè)新的承諾。在返回新的Promise之前,它會(huì)嘗試解析先前Promise使用的結(jié)果。我們將map先前Promise的結(jié)果轉(zhuǎn)換為新的Promise,然后回到在我們的map方法中實(shí)例化的新創(chuàng)建的Promise的范圍內(nèi)。.then我們可以繼續(xù)這種模式,根據(jù)需要附加盡可能多的回調(diào),并始終返回一個(gè)新的Promise,而無需在我們的map方法之外外部實(shí)例化任何新的Promise。(resolve,reject)=>this.then(...))正在發(fā)生的事情是我們this.then立即打電話。thethis指的是我們當(dāng)前的Promise,因此this.then將為我們提供Promise當(dāng)前的內(nèi)部值,或者如果我們的Promise失敗則給出當(dāng)前的錯(cuò)誤。我們現(xiàn)在需要給它一個(gè)resolve回調(diào)reject://nextresolve=x=>resolve(mapper(x))//nextreject=reject這是我們的地圖功能中最重要的部分。首先,我們用mapper當(dāng)前值填充我們的函數(shù)x:promise.map(x=>x+1)//Themapperisactuallyx=>x+1//sowhenwedomapper(10)//itreturns11.我們直接將這個(gè)新值(11在示例中)傳遞給resolve我們正在創(chuàng)建的新Promise的函數(shù)。如果Promise被拒絕,我們只需傳遞新的拒絕方法,而不對(duì)值進(jìn)行任何修改。
map(mapper){
returnnewPromise((resolve,reject)=>this.then(
x=>resolve(mapper(x)),
reject
))
}constpromise=newPromise((resolve,reject)=>{
setTimeout(()=>resolve(10),1000)})promise
.map(x=>x+1)//=>Promise(11)
.then(x=>console.log(x),err=>console.error(err))//=>it'sgoingtolog'11'總而言之,我們?cè)谶@里所做的事情非常簡(jiǎn)單。我們只是用映射器函數(shù)和下一個(gè)函數(shù)的組合resolve來覆蓋我們的函數(shù)。
這會(huì)將我們的值傳遞給映射器并解析返回的值。resolvex多使用我們的Promise實(shí)現(xiàn):constgetItems=newPromise((resolve,reject)=>{
HTTP.get('/items',(err,body)=>{
if(err)returnreject(err)
resolve(body)
})})getItems
.map(JSON.parse)
.map(json=>json.data)
.map(items=>items.filter(isEven))
.map(items=>items.sort(priceAsc))
.then(renderPrices,console.error)就像這樣,我們就被束縛了。我們鏈接的每個(gè)回調(diào)都是一個(gè)有點(diǎn)死的簡(jiǎn)單函數(shù)。這就是為什么我們喜歡在函數(shù)式編程中進(jìn)行柯里化?,F(xiàn)在我們可以編寫以下代碼:getItems
.map(JSON.parse)
.map(prop('data'))
.map(filter(isEven))
.map(sort(priceAsc))
.then(renderPrices,console.error)可以說,鑒于您更熟悉函數(shù)語法,您可以說這段代碼更干凈。另一方面,如果您不熟悉函數(shù)語法,那么這段代碼會(huì)變得非?;靵y。因此,為了更好地理解我們正在做的事情,讓我們明確定義我們的.then()方法在每次調(diào)用時(shí)將如何轉(zhuǎn)換.map:步驟1:newPromise((resolve,reject)=>{
HTTP.get('/items',(err,body)=>{
if(err)returnreject(err)
resolve(body)
})})第2步:.then現(xiàn)在:then=(resolve,reject)=>{
HTTP.get('/items',(err,body)=>{
if(err)returnreject(err)
resolve(body)
})}
.map(JSON.parse).then就是現(xiàn)在:then=(resolve,reject)=>{
HTTP.get('/items',(err,body)=>{
if(err)returnreject(err)
resolve(JSON.parse(body))
})}步驟3:
.map(x=>x.data).then就是現(xiàn)在:then=(resolve,reject)=>{
HTTP.get('/items',(err,body)=>{
if(err)returnreject(err)
resolve(JSON.parse(body).data)
})}步驟4:
.map(items=>items.filter(isEven)).then就是現(xiàn)在:then=(resolve,reject)=>{
HTTP.get('/items',(err,body)=>{
if(err)returnreject(err)
resolve(JSON.parse(body).data.filter(isEven))
})}第6步:
.map(items=>items.sort(priceAsc)).then就是現(xiàn)在:then=(resolve,reject)=>{
HTTP.get('/items',(err,body)=>{
if(err)returnreject(err)
resolve(JSON.parse(body).data.filter(isEven).sort(priceAsc))
})}第6步:
.then(renderPrices,console.error).then叫做。我們執(zhí)行的代碼如下所示:HTTP.get('/items',(err,body)=>{
if(err)returnconsole.error(err)
renderMales(JSON.parse(body).data.filter(isEven).sort(priceAsc))})3.鏈接和flatMap()我們的Promise實(shí)現(xiàn)仍然缺少一些東西——鏈接。當(dāng)您在方法內(nèi)返回另一個(gè)Promise時(shí).then,它??會(huì)等待它解析并將解析的值傳遞給下一個(gè).then內(nèi)部函數(shù)。這個(gè)工作怎么樣?在一個(gè)Promise中,.then也在壓扁這個(gè)promise容器。數(shù)組類比為flatMap:[1,2,3,4,5].map(x=>[x,x+1])//=>[[1,2],[2,3],[3,4],[4,5],[5,6]][1,2,3,4,5].flatMap(x=>[x,x+1])//=>[1,2,2,3,3,4,4,5,5,6]getPerson.flatMap(person=>getFriends(person))//=>Promise(Promise([Person]))getPerson.flatMap(person=>getFriends(person))//=>Promise([Person])這是我們的簽名細(xì)分,但如果很難理解,我建議您嘗試多次追蹤邏輯尾部,如果它沒有點(diǎn)擊,則嘗試深入研究下面的直接實(shí)現(xiàn)。我們非常深入,并且沒有函數(shù)式編程的經(jīng)驗(yàn),這種語法可能很難跟蹤,但請(qǐng)盡力而為,讓我們繼續(xù)下面的內(nèi)容。classPromise{
constructor(then)
{
this.then=then
}
map(mapper)
{
returnnewPromise(
(resolve,reject)=>this.then(
x=>resolve(mapper(x)),
reject
)
)
}
flatMap(mapper){
returnnewPromise(
(resolve,reject)=>this.then(
x=>mapper(x).then(resolve,reject),
reject
)
)
}}我們知道的flatMap映射器函數(shù)將返回一個(gè)Promise。當(dāng)我們得到值x時(shí),我們調(diào)用映射器,然后通過調(diào)用.then返回的Promise來轉(zhuǎn)發(fā)我們的resolve和reject函數(shù)。getPerson
.map(JSON.parse)
.map(x=>x.data)
.flatMap(person=>getFriends(person))
.map(json=>json.data)
.map(friends=>friends.filter(isMale))
.map(friends=>friends.sort(ageAsc))
.then(renderMaleFriends,console.error)怎么樣:)我們實(shí)際上通過分離Promise的不同行為來創(chuàng)建一個(gè)Monad。簡(jiǎn)單地說,monad是一個(gè)容器,它實(shí)現(xiàn)了具有以下類型簽名的.map方法.flatMap:map::(a->b)->Monada->MonadbflatMap::(a->Monadb)->Monada->Monadb該flatMap方法也稱為chain或bind。我們剛剛構(gòu)建的實(shí)際上稱為任務(wù),方法.then通常命名為fork。classTask{
constructor(fork)
{
this.fork=fork
}
map(mapper)
{
returnnewTask((resolve,reject)=>this.fork(
x=>resolve(mapper(x)),
reject
))
}
chain(mapper)
{
returnnewTask((resolve,reject)=>this.fork(
x=>mapper(x).fork(resolve,reject),
reject
))
}}Task和Promise之間的主要區(qū)別在于
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 二年級(jí)上冊(cè)數(shù)學(xué)教案-練習(xí)七-北師大版
- 六年級(jí)上冊(cè)數(shù)學(xué)教案-3.1 倒-數(shù) |西師大版
- 六年級(jí)下冊(cè)數(shù)學(xué)教案-4.1扇形統(tǒng)計(jì)圖的認(rèn)識(shí) ︳西師大版
- 三年級(jí)上冊(cè)數(shù)學(xué)教案-解決問題第一課時(shí)|蘇教版
- 六年級(jí)上冊(cè)數(shù)學(xué)教案 -2.1 分?jǐn)?shù)混合運(yùn)算|北師大版
- 融資擔(dān)保培訓(xùn)協(xié)議書(2篇)
- 北師大版數(shù)學(xué)三年級(jí)上冊(cè)單元測(cè)試卷-第三單元-加與減(含答案)
- 2024年血壓調(diào)節(jié)用品項(xiàng)目資金籌措計(jì)劃書代可行性研究報(bào)告
- 2025年度兩人共同投資可再生能源項(xiàng)目的股份合作合同
- 2025年度合伙人退出與合作伙伴關(guān)系維護(hù)協(xié)議
- 拉線的制作詳細(xì)
- 律師報(bào)價(jià)函(訴訟)
- 新生兒沐浴評(píng)分標(biāo)準(zhǔn)
- 潛水作業(yè)指導(dǎo)書
- (完整版)設(shè)計(jì)管理
- 感謝對(duì)手閱讀附答案
- 材料性能學(xué)(第2版)付華課件0-緒論-材料性能學(xué)
- GB/T 8012-2000鑄造錫鉛焊料
- 第一課 第一章 AutoCAD 2012概述入門
- 2023年湖南省普通高中學(xué)業(yè)水平考試數(shù)學(xué)版含答案
- 超市店長(zhǎng)考核方案(實(shí)例)
評(píng)論
0/150
提交評(píng)論