【全棧React】第15天: Promise簡介

本文轉載自:衆成翻譯
譯者: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

Promise

正如 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');
});

以這種方式處理 異步 會很快變得複雜。此外, 咱們能夠從之前的函數調用中獲取值, 若是咱們只想獲得一個... 在處理應用啓動時尚未的值時, 有不少棘手的狀況須要處理。

進入Promise

使用承諾, 另外一方面幫助咱們避免了不少這種複雜性 (雖然不是一個銀彈解決方案,參考《人月神話》)。之前的代碼, 這能夠被稱爲意大利麪條代碼能夠變成一個更整潔, 更同步的前瞻版本:

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))

單使用Guarantee

承諾在任何特定的時間都只應該在三種狀態之一:

  • 待定
  • 已完成 (已解決)
  • 已拒絕 (錯誤)

一個 待定 的承諾只能致使一個知足狀態或一個被拒絕的狀態 一次且僅一次 , 這能夠避免一些至關複雜的錯誤場景。這意味着, 咱們只能返回一個承諾一次。若是咱們想從新運行一個使用承諾的函數, 咱們須要建立一個 的。

建立一個Promise

咱們可使用 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() 庫。

相關文章
相關標籤/搜索