成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

初學(xué)者應(yīng)該看的JavaScript Promise 完整指南

開發(fā)
這篇文章算是 JavaScript Promises 比較全面的教程,該文介紹了必要的方法,例如 then,catch和finally。此外,還包括處理更復(fù)雜的情況,例如與Promise.all并行執(zhí)行Promise,通過(guò)Promise.race 來(lái)處理請(qǐng)求超時(shí)的情況,Promise 鏈以及一些最佳實(shí)踐和常見的陷阱。

1.JavaScript Promises
Promise 是一個(gè)允許我們處理異步操作的對(duì)象,它是 es5 早期回調(diào)的替代方法。

[[342689]]

與回調(diào)相比,Promise 具有許多優(yōu)點(diǎn),例如:

讓異步代碼更易于閱讀。
提供組合錯(cuò)誤處理。* 更好的流程控制,可以讓異步并行或串行執(zhí)行。
回調(diào)更容易形成深度嵌套的結(jié)構(gòu)(也稱為回調(diào)地獄)。如下所示:

  1. a(() => { 
  2.   b(() => { 
  3.     c(() => { 
  4.       d(() => { 
  5.         // and so on ... 
  6.       });    });  });}); 

如果將這些函數(shù)轉(zhuǎn)換為 Promise,則可以將它們鏈接起來(lái)以生成更可維護(hù)的代碼。像這樣:

  1. Promise.resolve() 
  2.   .then(a) 
  3.   .then(b) 
  4.   .then(c) 
  5.   .then(d) 
  6.   .catch(console.error); 

在上面的示例中,Promise 對(duì)象公開了.then和.catch方法,我們稍后將探討這些方法。

1.1 如何將現(xiàn)有的回調(diào) API 轉(zhuǎn)換為 Promise?
我們可以使用 Promise 構(gòu)造函數(shù)將回調(diào)轉(zhuǎn)換為 Promise。

Promise 構(gòu)造函數(shù)接受一個(gè)回調(diào),帶有兩個(gè)參數(shù)resolve和reject。

Resolve:是在異步操作完成時(shí)應(yīng)調(diào)用的回調(diào)。
Reject:是發(fā)生錯(cuò)誤時(shí)要調(diào)用的回調(diào)函數(shù)。
構(gòu)造函數(shù)立即返回一個(gè)對(duì)象,即 Promise 實(shí)例。當(dāng)在 promise 實(shí)例中使用.then方法時(shí),可以在Promise “完成” 時(shí)得到通知。讓我們來(lái)看一個(gè)例子。

Promise 僅僅只是回調(diào)?
并不是。承諾不僅僅是回調(diào),但它們確實(shí)對(duì).then和.catch方法使用了異步回調(diào)。Promise 是回調(diào)之上的抽象,我們可以鏈接多個(gè)異步操作并更優(yōu)雅地處理錯(cuò)誤。來(lái)看看它的實(shí)際效果。

Promise 反面模式(Promises 地獄)

  1. a(() => { 
  2.   b(() => { 
  3.     c(() => { 
  4.       d(() => { 
  5.         // and so on ... 
  6.       });    });  });}); 

不要將上面的回調(diào)轉(zhuǎn)成下面的 Promise 形式:

  1. a().then(() => { 
  2.   return b().then(() => { 
  3.     return c().then(() => { 
  4.       return d().then(() =>{ 
  5.         // ⚠️ Please never ever do to this! ⚠️ 
  6.       });    });  });}); 

上面的轉(zhuǎn)成,也形成了 Promise 地獄,千萬(wàn)不要這么轉(zhuǎn)。相反,下面這樣做會(huì)好點(diǎn):

  1. a() 
  2.   .then(b) 
  3.   .then(c) 
  4.   .then(d) 

超時(shí)
你認(rèn)為以下程序的輸出的是什么?

  1. const promise = new Promise((resolve, reject) => { 
  2.   setTimeout(() => { 
  3.     resolve('time is up ⏰'); 
  4.   }, 1e3); 
  5.   setTimeout(() => { 
  6.     reject('Oops '); 
  7.   }, 2e3); 
  8. });promise  .then(console.log) 
  9.   .catch(console.error); 

是輸出:

  1. time is up ⏰ 
  2. Oops!  

還是輸出:

  1. time is up ⏰ 

是后者,因?yàn)楫?dāng)一個(gè)Promise resolved 后,它就不能再被rejected。

一旦你調(diào)用一種方法(resolve 或reject),另一種方法就會(huì)失效,因?yàn)?promise 處于穩(wěn)定狀態(tài)。讓我們探索一個(gè) promise 的所有不同狀態(tài)。

1.2 Promise 狀態(tài)
Promise 可以分為四個(gè)狀態(tài):

⏳ Pending:初始狀態(tài),異步操作仍在進(jìn)行中。
✅ Fulfilled:操作成功,它調(diào)用.then回調(diào),例如.then(onSuccess)。
⛔️ Rejected: 操作失敗,它調(diào)用.catch或.then的第二個(gè)參數(shù)(如果有)。例如.catch(onError)或.then(..., onError)。
Settled:這是 promise 的最終狀態(tài)。promise 已經(jīng)死亡了,沒(méi)有別的辦法可以解決或拒絕了。.finally方法被調(diào)用

1.3 Promise 實(shí)例方法
Promise API 公開了三個(gè)主要方法:then,catch和finally。我們逐一配合事例探討一下。

Promise then
then方法可以讓異步操作成功或失敗時(shí)得到通知。它包含兩個(gè)參數(shù),一個(gè)用于成功執(zhí)行,另一個(gè)則在發(fā)生錯(cuò)誤時(shí)使用。

  1. promise.then(onSuccess, onError); 

你還可以使用catch來(lái)處理錯(cuò)誤:

  1. promise.then(onSuccess).catch(onError); 

Promise 鏈
then 返回一個(gè)新的 Promise ,這樣就可以將多個(gè)Promise 鏈接在一起。就像下面的例子一樣:

  1. Promise.resolve() 
  2.   .then(() => console.log('then#1')) 
  3.   .then(() => console.log('then#2')) 
  4.   .then(() => console.log('then#3')); 

Promise.resolve立即將Promise 視為成功。因此,以下所有內(nèi)容都將被調(diào)用。輸出將是

  1. then#1 
  2. then#2 
  3. then#3 

Promise catch
Promise .catch方法將函數(shù)作為參數(shù)處理錯(cuò)誤。如果沒(méi)有出錯(cuò),則永遠(yuǎn)不會(huì)調(diào)用catch方法。

假設(shè)我們有以下承諾:1秒后解析或拒絕并打印出它們的字母。

  1. const a = () => new Promise((resolve) => setTimeout(() => { console.log('a'), resolve() }, 1e3)); 
  2. const b = () => new Promise((resolve) => setTimeout(() => { console.log('b'), resolve() }, 1e3)); 
  3. const c = () => new Promise((resolve, reject) => setTimeout(() => { console.log('c'), reject('Oops!') }, 1e3)); 
  4. const d = () => new Promise((resolve) => setTimeout(() => { console.log('d'), resolve() }, 1e3)); 

請(qǐng)注意,c使用reject('Oops!')模擬了拒絕。

  1. Promise.resolve() 
  2.   .then(a) 
  3.   .then(b) 
  4.   .then(c) 
  5.   .then(d) 
  6.   .catch(console.error) 

輸出如下:

在這種情況下,可以看到a,b和c上的錯(cuò)誤消息。

我們可以使用then函數(shù)的第二個(gè)參數(shù)來(lái)處理錯(cuò)誤。但是,請(qǐng)注意,catch將不再執(zhí)行。

  1. Promise.resolve() 
  2.   .then(a) 
  3.   .then(b) 
  4.   .then(c) 
  5.   .then(d, () => console.log('c errored out but no big deal')) 
  6.   .catch(console.error) 

由于我們正在處理 .then(..., onError)部分的錯(cuò)誤,因此未調(diào)用catch。d不會(huì)被調(diào)用。如果要忽略錯(cuò)誤并繼續(xù)執(zhí)行Promise鏈,可以在c上添加一個(gè)catch。像這樣:

  1. Promise.resolve() 
  2.   .then(a) 
  3.   .then(b) 
  4.   .then(() => c().catch(() => console.log('error ignored'))) 
  5.   .then(d) 
  6.   .catch(console.error) 

當(dāng)然,這種過(guò)早的捕獲錯(cuò)誤是不太好的,因?yàn)槿菀自谡{(diào)試過(guò)程中忽略一些潛在的問(wèn)題。

Promise finally
finally方法只在 Promise 狀態(tài)是 settled 時(shí)才會(huì)調(diào)用。

如果你希望一段代碼即使出現(xiàn)錯(cuò)誤始終都需要執(zhí)行,那么可以在.catch之后使用.then。

  1. Promise.resolve() 
  2.   .then(a) 
  3.   .then(b) 
  4.   .then(c) 
  5.   .then(d) 
  6.   .catch(console.error) 
  7.   .then(() => console.log('always called')); 

或者可以使用.finally關(guān)鍵字:

  1. Promise.resolve() 
  2.   .then(a) 
  3.   .then(b) 
  4.   .then(c) 
  5.   .then(d) 
  6.   .catch(console.error) 
  7.   .finally(() => console.log('always called')); 

1.4 Promise 類方法
我們可以直接使用 Promise 對(duì)象中四種靜態(tài)方法。

 

  1. Promise.all 
  2. Promise.reject 
  3. Promise.resolve 
  4. Promise.race 

 

Promise.resolve 和 Promise.reject
這兩個(gè)是幫助函數(shù),可以讓 Promise 立即解決或拒絕。可以傳遞一個(gè)參數(shù),作為下次 .then 的接收:

  1. Promise.resolve('Yay!!!'
  2.   .then(console.log) 
  3.   .catch(console.error) 

上面會(huì)輸出 Yay!!!

  1. Promise.reject('Oops '
  2.   .then(console.log) 
  3.   .catch(console.error) 

使用 Promise.all 并行執(zhí)行多個(gè) Promise
通常,Promise 是一個(gè)接一個(gè)地依次執(zhí)行的,但是你也可以并行使用它們。

假設(shè)是從兩個(gè)不同的api中輪詢數(shù)據(jù)。如果它們不相關(guān),我們可以使用Promise.all()同時(shí)觸發(fā)這兩個(gè)請(qǐng)求。

在此示例中,主要功能是將美元轉(zhuǎn)換為歐元,我們有兩個(gè)獨(dú)立的 API 調(diào)用。一種用于BTC/USD,另一種用于獲得EUR/USD。如你所料,兩個(gè) API 調(diào)用都可以并行調(diào)用。但是,我們需要一種方法來(lái)知道何時(shí)同時(shí)完成最終價(jià)格的計(jì)算。我們可以使用Promise.all,它通常在啟動(dòng)多個(gè)異步任務(wù)并發(fā)運(yùn)行并為其結(jié)果創(chuàng)建承諾之后使用,以便人們可以等待所有任務(wù)完成。

  1. const axios = require('axios'); 
  2. const bitcoinPromise = axios.get('https://api.coinpaprika.com/v1/coins/btc-bitcoin/markets'); 
  3. const dollarPromise = axios.get('https://api.exchangeratesapi.io/latest?base=USD'); 
  4. const currency = 'EUR'
  5. // Get the price of bitcoins on 
  6. Promise.all([bitcoinPromise, dollarPromise])  .then(([bitcoinMarkets, dollarExchanges]) => { 
  7.     const byCoinbaseBtc = d => d.exchange_id === 'coinbase-pro' && d.pair === 'BTC/USD'
  8.     const coinbaseBtc = bitcoinMarkets.data.find(byCoinbaseBtc)    const coinbaseBtcInUsd = coinbaseBtc.quotes.USD.price;    const rate = dollarExchanges.data.rates[currency];    return rate * coinbaseBtcInUsd; 
  9.   })  .then(price => console.log(`The Bitcoin in ${currency} is ${price.toLocaleString()}`)) 
  10.   .catch(console.log) 

如你所見,Promise.all接受了一系列的 Promises。當(dāng)兩個(gè)請(qǐng)求的請(qǐng)求都完成后,我們就可以計(jì)算價(jià)格了。

我們?cè)倥e一個(gè)例子:

  1. const a = () => new Promise((resolve) => setTimeout(() => resolve('a'), 2000)); 
  2. const b = () => new Promise((resolve) => setTimeout(() => resolve('b'), 1000)); 
  3. const c = () => new Promise((resolve) => setTimeout(() => resolve('c'), 1000)); 
  4. const d = () => new Promise((resolve) => setTimeout(() => resolve('d'), 1000)); 
  5. console.time('promise.all'); 
  6. Promise.all([a(), b(), c(), d()])  .then(results => console.log(`Done! ${results}`)) 
  7.   .catch(console.error) 
  8.   .finally(() => console.timeEnd('promise.all')); 

解決這些 Promise 要花多長(zhǎng)時(shí)間?5秒?1秒?還是2秒?

這個(gè)留給你們自己驗(yàn)證咯。

Promise race
Promise.race(iterable) 方法返回一個(gè) promise,一旦迭代器中的某個(gè)promise解決或拒絕,返回的 promise就會(huì)解決或拒絕。

  1. const a = () => new Promise((resolve) => setTimeout(() => resolve('a'), 2000)); 
  2. const b = () => new Promise((resolve) => setTimeout(() => resolve('b'), 1000)); 
  3. const c = () => new Promise((resolve) => setTimeout(() => resolve('c'), 1000)); 
  4. const d = () => new Promise((resolve) => setTimeout(() => resolve('d'), 1000)); 
  5. console.time('promise.race'); 
  6. Promise.race([a(), b(), c(), d()])  .then(results => console.log(`Done! ${results}`)) 
  7.   .catch(console.error) 
  8.   .finally(() => console.timeEnd('promise.race')); 

輸出是什么?

輸出 b。使用 Promise.race,最先執(zhí)行完成就會(huì)結(jié)果最后的返回結(jié)果。

你可能會(huì)問(wèn):Promise.race的用途是什么?

我沒(méi)胡經(jīng)常使用它。但是,在某些情況下,它可以派上用場(chǎng),比如計(jì)時(shí)請(qǐng)求或批量處理請(qǐng)求數(shù)組。

  1. Promise.race([ 
  2.   fetch('http://slowwly.robertomurray.co.uk/delay/3000/url/https://api.jsonbin.io/b/5d1fb4dd138da811182c69af'), 
  3.   new Promise((resolve, reject) => setTimeout(() => reject(new Error('request timeout')), 1000)) 
  4. ]).then(console.log) 
  5. .catch(console.error); 

如果請(qǐng)求足夠快,那么就會(huì)得到請(qǐng)求的結(jié)果。

 

1.5 Promise 常見問(wèn)題
串行執(zhí)行 promise 并傳遞參數(shù)

這次,我們將對(duì)Node的fs使用promises API,并將兩個(gè)文件連接起來(lái):

  1. const fs = require('fs').promises; // requires node v8+ 
  2. fs.readFile('file.txt''utf8'
  3.   .then(content1 => fs.writeFile('output.txt', content1)) 
  4.   .then(() => fs.readFile('file2.txt''utf8')) 
  5.   .then(content2 => fs.writeFile('output.txt', content2, { flag: 'a+' })) 
  6.   .catch(error => console.log(error)); 

在此示例中,我們讀取文件1并將其寫入output 文件。稍后,我們讀取文件2并將其再次附加到output文件。如你所見,writeFile promise返回文件的內(nèi)容,你可以在下一個(gè)then子句中使用它。

如何鏈接多個(gè)條件承諾?
你可能想要跳過(guò) Promise 鏈上的特定步驟。有兩種方法可以做到這一點(diǎn)。

  1. const a = () => new Promise((resolve) => setTimeout(() => { console.log('a'), resolve() }, 1e3)); 
  2. const b = () => new Promise((resolve) => setTimeout(() => { console.log('b'), resolve() }, 2e3)); 
  3. const c = () => new Promise((resolve) => setTimeout(() => { console.log('c'), resolve() }, 3e3)); 
  4. const d = () => new Promise((resolve) => setTimeout(() => { console.log('d'), resolve() }, 4e3)); 
  5. const shouldExecA = true
  6. const shouldExecB = false
  7. const shouldExecC = false
  8. const shouldExecD = true
  9. Promise.resolve()  .then(() => shouldExecA && a()) 
  10.   .then(() => shouldExecB && b()) 
  11.   .then(() => shouldExecC && c()) 
  12.   .then(() => shouldExecD && d()) 
  13.   .then(() => console.log('done')) 

如果你運(yùn)行該代碼示例,你會(huì)注意到只有a和d被按預(yù)期執(zhí)行。

另一種方法是創(chuàng)建一個(gè)鏈,然后僅在以下情況下添加它們:

  1. const chain = Promise.resolve(); 
  2. if (shouldExecA) chain = chain.then(a); 
  3. if (shouldExecB) chain = chain.then(b); 
  4. if (shouldExecC) chain = chain.then(c); 
  5. if (shouldExecD) chain = chain.then(d); 
  6. chain  .then(() => console.log('done')); 

如何限制并行 Promise?
要做到這一點(diǎn),我們需要以某種方式限制Promise.all。

假設(shè)你有許多并發(fā)請(qǐng)求要執(zhí)行。如果使用 Promise.all 是不好的(特別是在API受到速率限制時(shí))。因此,我們需要一個(gè)方法來(lái)限制 Promise 個(gè)數(shù), 我們稱其為promiseAllThrottled。

  1. // simulate 10 async tasks that takes 5 seconds to complete. 
  2. const requests = Array(10) 
  3.   .fill()  .map((_, i) => () => new Promise((resolve => setTimeout(() => { console.log(`exec'ing task #${i}`), resolve(`task #${i}`); }, 5000)))); 
  4. promiseAllThrottled(requests, { concurrency: 3 }) 
  5.   .then(console.log) 
  6.   .catch(error => console.error('Oops something went wrong', error)); 

輸出應(yīng)該是這樣的:

以上代碼將并發(fā)限制為并行執(zhí)行的3個(gè)任務(wù)。

實(shí)現(xiàn)promiseAllThrottled 一種方法是使用Promise.race來(lái)限制給定時(shí)間的活動(dòng)任務(wù)數(shù)量。

  1. /** 
  2.  * Similar to Promise.all but a concurrency limit 
  3.  * 
  4.  * @param {Array} iterable Array of functions that returns a promise 
  5.  * @param {Object} concurrency max number of parallel promises running 
  6.  */ 
  7. function promiseAllThrottled(iterable, { concurrency = 3 } = {}) { 
  8.   const promises = []; 
  9.   function enqueue(current = 0, queue = []) { 
  10.     // return if done 
  11.     if (current === iterable.length) { return Promise.resolve(); } 
  12.     // take one promise from collection 
  13.     const promise = iterable[current]; 
  14.     const activatedPromise = promise(); 
  15.     // add promise to the final result array 
  16.     promises.push(activatedPromise); 
  17.     // add current activated promise to queue and remove it when done 
  18.     const autoRemovePromise = activatedPromise.then(() => { 
  19.       // remove promise from the queue when done 
  20.       return queue.splice(queue.indexOf(autoRemovePromise), 1); 
  21.     }); 
  22.     // add promise to the queue 
  23.     queue.push(autoRemovePromise); 
  24.     // if queue length >= concurrency, wait for one promise to finish before adding more. 
  25.     const readyForMore = queue.length < concurrency ? Promise.resolve() : Promise.race(queue); 
  26.     return readyForMore.then(() => enqueue(current + 1, queue)); 
  27.   } 
  28.   return enqueue() 
  29.     .then(() => Promise.all(promises)); 

promiseAllThrottled一對(duì)一地處理 Promises 。它執(zhí)行Promises并將其添加到隊(duì)列中。如果隊(duì)列小于并發(fā)限制,它將繼續(xù)添加到隊(duì)列中。達(dá)到限制后,我們使用Promise.race等待一個(gè)承諾完成,因此可以將其替換為新的承諾。這里的技巧是,promise 自動(dòng)完成后會(huì)自動(dòng)從隊(duì)列中刪除。另外,我們使用 race 來(lái)檢測(cè)promise 何時(shí)完成,并添加新的 promise 。

 

責(zé)任編輯:姜華 來(lái)源: 今日頭條
相關(guān)推薦

2020-07-29 08:26:40

Webpack前端模塊

2024-01-12 14:37:29

智能家居人工智能

2022-04-24 15:21:01

MarkdownHTML

2021-05-06 09:00:00

JavaScript靜態(tài)代碼開發(fā)

2020-12-15 14:05:15

云計(jì)算

2022-07-22 13:14:57

TypeScript指南

2010-06-13 11:13:38

UML初學(xué)者指南

2021-05-10 08:50:32

網(wǎng)絡(luò)管理網(wǎng)絡(luò)網(wǎng)絡(luò)性能

2023-07-28 07:31:52

JavaScriptasyncawait

2022-03-28 09:52:42

JavaScript語(yǔ)言

2023-07-03 15:05:07

預(yù)測(cè)分析大數(shù)據(jù)

2022-10-10 15:28:45

負(fù)載均衡

2018-10-28 16:14:55

Reactreact.js前端

2010-08-26 15:47:09

vsftpd安裝

2023-02-10 08:37:28

2012-03-14 10:56:23

web app

2022-09-05 15:36:39

Linux日志記錄syslogd

2018-05-14 08:53:51

Linux命令shuf

2024-12-25 08:00:00

機(jī)器學(xué)習(xí)ML管道人工智能

2013-04-08 16:35:52

Adobe Edge
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 日日碰狠狠躁久久躁婷婷 | 男女羞羞视频免费 | 国产精品视频在线免费观看 | 91在线观看网址 | www.成人免费视频 | 欧美一级二级三级视频 | 国产一区二区毛片 | 日韩在线播放视频 | 97在线观看| 九九av | 欧美一级久久久猛烈a大片 日韩av免费在线观看 | 日日夜夜精品免费视频 | 国产一区二区视频在线 | 日韩在线一区二区三区 | 一个色在线 | 亚洲一区二区久久 | 福利av在线 | 日韩无 | 91观看| 国产激情视频 | 亚洲精品18 | 免费观看av | 国产综合在线视频 | 性生生活大片免费看视频 | 99re视频这里只有精品 | 亚洲精品www. | 成人av一区二区三区 | 免费国产视频在线观看 | 国产.com| 在线成人免费视频 | 成人二区三区 | 中文字幕一区二区三区四区五区 | 人人九九精| 国产精品久久久久久久久污网站 | 中文字幕的av | 久久精品小短片 | 久久久高清 | 成人三区 | 91精品国产综合久久婷婷香蕉 | 国产精品无码久久久久 | 国产黄色大片 |