本文轉載自:衆成翻譯
譯者:iOSDevLog
連接:http://www.zcfy.cc/article/3814
原文:https://www.fullstackreact.com/30-days-of-react/day-15/javascript
今天,咱們將要看看咱們須要知道什麼來從高層次瞭解Promises,因此咱們可使用這個很是有用的概念構建咱們的應用。java
昨天咱們將 fetch
庫安裝到咱們的 create-react-app
項目 咱們開始 第12天. 今天, 咱們將拿起從昨天討論的概念和Promises的 藝術 .react
正如 mozilla 所定義的, 承諾
對象用於處理異步計算, 其中有一些重要的保證難以用回調方法處理 (更老式的處理異步代碼的方法)。api
Promise
對象只是圍繞一個值的包裝, 它在實例化對象時可能也可能不知道, 並提供了一個已知的 (也稱爲 resolved
) 或因爲失敗緣由而不可用 (咱們將此稱爲rejected
) 後 處理該值的方法 。promise
使用 "承諾" 對象使咱們有機會將異步操做的最終成功或失敗關聯到功能 (不管出於何種緣由)。它還容許咱們使用相似於同步的代碼來處理這些複雜的場景。瀏覽器
例如, 考慮下面的同步代碼, 咱們在 javascript 控制檯中打印出當前時間:服務器
var currentTime = new Date(); console.log('The current time is: ' + currentTime);
這是至關直接的, 並做爲 new Date()
對象表示瀏覽器知道的時間。如今考慮咱們在其餘遠程機器上使用不一樣的時鐘。例如, 若是咱們正在作一個快樂的新年時鐘, 這將是偉大的, 可以同步用戶的瀏覽器與其餘人使用一個單一的時間值爲每一個人, 因此沒有人錯過的落球儀式。。app
假設咱們有一個方法來處理從遠程服務器獲取當前時間的 getCurrentTime()
時鐘。如今, 咱們將用setTimeout()
來表示這一點, 它返回時間 (就像對慢速 api 發出請求同樣):dom
function getCurrentTime() { // Get the current 'global' time from an API return setTimeout(function() { return new Date(); }, 2000); } var currentTime = getCurrentTime() console.log('The current time is: ' + currentTime);
咱們的console.log()
日誌值將返回超時處理程序 id, 這絕對 不是 當前時間。傳統上, 咱們可使用回調來更新代碼, 以便在可用時間時調用:異步
function getCurrentTime(callback) { // Get the current 'global' time from an API return setTimeout(function() { var currentTime = new Date(); callback(currentTime); }, 2000); } getCurrentTime(function(currentTime) { console.log('The current time is: ' + currentTime); });
若是有其他的錯誤呢?咱們如何捕獲錯誤並定義重試或錯誤狀態?
function getCurrentTime(onSuccess, onFail) { // Get the current 'global' time from an API return setTimeout(function() { // randomly decide if the date is retrieved or not var didSucceed = Math.random() >= 0.5; if (didSucceed) { var currentTime = new Date(); onSuccess(currentTime); } else { onFail('Unknown error'); } }, 2000); } getCurrentTime(function(currentTime) { console.log('The current time is: ' + currentTime); }, function(error) { console.log('There was an error fetching the time'); });
如今, 若是咱們想根據第一個請求的值提出請求怎麼辦?做爲一個簡短的示例, 讓咱們再次重用 getCurrentTime()
函數 (就好像它是第二個方法, 但容許咱們避免添加另外一個複雜的函數):
function getCurrentTime(onSuccess, onFail) { // Get the current 'global' time from an API return setTimeout(function() { // randomly decide if the date is retrieved or not var didSucceed = Math.random() >= 0.5; console.log(didSucceed); if (didSucceed) { var currentTime = new Date(); onSuccess(currentTime); } else { onFail('Unknown error'); } }, 2000); } getCurrentTime(function(currentTime) { getCurrentTime(function(newCurrentTime) { console.log('The real current time is: ' + currentTime); }, function(nestedError) { console.log('There was an error fetching the second time'); }) }, function(error) { console.log('There was an error fetching the time'); });
以這種方式處理 異步 會很快變得複雜。此外, 咱們能夠從之前的函數調用中獲取值, 若是咱們只想獲得一個... 在處理應用啓動時尚未的值時, 有不少棘手的狀況須要處理。
使用承諾, 另外一方面幫助咱們避免了不少這種複雜性 (雖然不是一個銀彈解決方案,參考《人月神話》)。之前的代碼, 這能夠被稱爲意大利麪條代碼能夠變成一個更整潔, 更同步的前瞻版本:
function getCurrentTime(onSuccess, onFail) { // Get the current 'global' time from an API using Promise return new Promise((resolve, reject) => { setTimeout(function() { var didSucceed = Math.random() >= 0.5; didSucceed ? resolve(new Date()) : reject('Error'); }, 2000); }) } getCurrentTime() .then(currentTime => getCurrentTime()) .then(currentTime => { console.log('The current time is: ' + currentTime); return true; }) .catch(err => console.log('There was an error:' + err))
之前的源代碼示例對正在發生的事情進行了一些清理和清除, 避免了許多棘手的錯誤處理/捕獲。
爲了得到成功的值, 咱們將使用Promise
實例對象上的 then()
功能。then()
函數被調用, 不管返回值是Promise
自己。例如, 在上面的示例中, getCurrentTime()
函數解析爲currentTime()
值 (在成功完成時), 並在返回值 (這是另外一個承諾) 上調用then()
函數, 依此類推等等。
要捕獲在承諾鏈中任何地方發生的錯誤, 咱們可使用catch()
方法。
咱們在上面的例子中使用一個承諾鏈, 以建立一個 鏈 的行動, 被稱爲一個接一個。
承諾鏈聽起來很複雜, 但基本上很簡單。實質上, 咱們能夠連續地 "同步" 調用多個異步操做。對then()
的每次調用都用之前的then()
函數的返回值來調用。
例如, 若是咱們想操縱getCurrentTime()
調用的值, 咱們能夠在鏈中添加一個連接, 以下所示:getCurrentTime() .then(currentTime => getCurrentTime()) .then(currentTime => { return 'It is now: ' + currentTime; }) // this logs: "It is now: [current time]" .then(currentTimeMessage => console.log(currentTimeMessage)) .catch(err => console.log('There was an error:' + err))
承諾在任何特定的時間都只應該在三種狀態之一:
一個 待定 的承諾只能致使一個知足狀態或一個被拒絕的狀態 一次且僅一次 , 這能夠避免一些至關複雜的錯誤場景。這意味着, 咱們只能返回一個承諾一次。若是咱們想從新運行一個使用承諾的函數, 咱們須要建立一個 新 的。
咱們可使用 Promise
構造函數來建立新的承諾 (如上面的示例所示)。它接受一個有兩個參數來運行的函數:
onSuccess
(or resolve
) 函數將在成功解析後被調用onFail
(or reject
) 函數在失敗拒絕後被調用從上面回顧咱們的函數, 咱們能夠看到, 若是請求成功, 咱們調用 resolve()
函數, 若是該方法返回錯誤條件, 則調用 reject()
函數。
var promise = new Promise(function(resolve, reject) { // call resolve if the method succeeds resolve(true); }) promise.then(bool => console.log('Bool is true'))
如今咱們知道了什麼是承諾, 如何使用, 以及如何建立它們, 咱們實際上可使用昨天安裝的 fetch()
庫。