[譯]ES6入門(第二部分)

原文戳這裏git

[譯]ES6入門(第一部分)程序員

[譯]ES6入門(第三部分)es6

這篇文章的第一部分出如今這裏。 我在那裏介紹了一些有趣的功能:)github

我將在這篇文章中介紹的主題包括:web

一、Promisesapi

二、Async / Awaitpromise

Promises

Promise是ES6中的一個有用功能。它們用於進行異步操做,例如API請求,文件處理,下載圖像等。服務器

那麼,什麼是異步? (繼續,若是你已經知道)異步

異步操做是須要一些時間才能完成的操做。async

例如,假設您正在定義向服務器發出API請求的函數。該函數不會當即返回結果,由於從服務器獲取響應須要幾秒鐘。

所以,若是您正在調用該函數並將其值(即)返回的結果分配給某個變量,那麼它將是未定義的。由於Javascript不知道該函數正在處理一些異步操做。

那咱們該如何處理呢?

讓咱們先談談一些歷史。

在Promise以前,程序員習慣於定義回調。回調是Javascript中的常規函數,它在異步操做完成時執行。

例如,您定義了一個向服務器發出API請求的函數。而後你設置了一個回調函數,它將在咱們從服務器得到響應時執行。

因此在上面的例子中,Javascript不會中止執行,直到咱們從API得到響應。咱們已經定義了一個函數(回調),它將在咱們獲得響應後執行。我想你明白了。

那麼,Promise是什麼?

Promise是有助於執行異步操做的對象。

從技術上講,它們是表示異步操做完成的對象。 (若是你不明白,請繼續往下閱讀一下子)

在解釋如何定義Promise以前,我將解釋Promise的生命週期。

在Promise中有三種狀態:

一、掛起:在這種狀態下,promise只是執行異步操做。例如,它正在向服務器發出一些API請求或從cdn下載一些圖像。 從這個狀態Promise能夠轉移到完成狀態或拒絕狀態

二、完成:若是Promise已達到此狀態,則表示異步操做已完成,而且獲得了輸出的結果。例如,咱們有了來自API的響應。

三、拒絕:若是Promise已達到此狀態,則表示異步操做未成功,而且咱們獲得致使操做失敗的錯誤。

好的..讓咱們看一些代碼。

const apiCall = new Promise(function(resolve, reject) {
 // 異步操做在這裏定義..
});
複製代碼

經過使用new關鍵字建立構造函數來定義Promise。 而後構造函數將有一個函數(咱們稱之爲執行函數。)

異步操做在執行函數內定義。

請注意,執行函數有兩個參數resolve和reject。

第一個參數resolve其實是一個函數。 它在執行函數內部調用,它表示異步操做成功,咱們獲得告終果。 resolve函數有助於Promise從掛起狀態轉爲完成狀態。 但願你明白了。:)

像resolve同樣,reject也是一個函數。 它也在執行函數內部調用,它表示異步操做不成功,咱們遇到了錯誤。 reject函數有助於Promise從掛起狀態轉爲拒絕狀態。:)

const apiCall = new Promise(function(resolve, reject) {
 if ( API request to get some data ) {
  resolve("The request is successful and the response is "+ response);
 }
 else {
  reject("The request is not successful. The error is "+error);
 }
});
複製代碼

在上面的代碼中,您能夠看到咱們在執行函數中完成了一些異步操做。 若是咱們從服務器得到響應,則調用resolve函數。 若是有錯誤,則會使用錯誤消息調用reject函數。

咱們已經完成了Promise。 讓咱們看看如何執行Promise並處理輸出。

// 調用promise.
apiCall
複製代碼

就是這樣。 結束了。 :) :)

開玩笑。 還沒結束。

在上面的代碼中,調用函數並執行promise(即執行函數)。 而後根據輸出調用resolve或reject函數。

可是你能夠看到咱們沒有處理promise中返回的輸出。

例如,若是咱們從API得到響應,那麼咱們必須處理響應。 或者若是咱們獲得錯誤,咱們須要正確處理它。

那咱們該如何處理呢?

咱們使用處理器來獲取promise的輸出。

處理器是在某些事件發生時執行的函數,例如單擊按鈕,移動光標等。

所以,當resolve函數被調用或reject函數被調用時,咱們可使用處理器來處理。

簡單。:)

咱們來看一些代碼

// 調用promise,並使用handlers.
apiCall.then(function(x) {console.log(x); })
複製代碼

在上面的代碼中,咱們將一個處理器then附加到promise。處理器then有一個函數參數。函數參數自己有一個參數x。

發生了什麼事?

當在promise內調用resolve函數時,處理器then執行其函數參數。

我會再解釋一次。

處理器then監聽resolve函數被調用時的事件。 所以,當調用resolve函數時,處理器then執行其函數參數。

apiCall.then(function(x) {console.log(x); })
// 輸出
The request is successful and the response is {name: "Jon Snow"}
複製代碼

一樣,還有另外一個處理器catch。

Catch監聽reject函數。

Catch函數在reject函數被調用時執行其函數參數。

apiCall.then(function(x) {console.log(x); }).catch(function(x) {console.log(x); })
// 假設這個請求沒有成功 (在promise中reject函數被調用. )
輸出:
The request is not successful
複製代碼

我想你明白了。

上面的代碼不太可讀。 因此讓咱們嘗試重構它。

apiCall
.then(function(x) {
 console.log(x); 
})
.catch(function(x) {
 console.log(x);
}) 
複製代碼

啊......如今可讀了。 大多數程序員都這樣寫。

好吧..因此我以爲你已經走了很長的路。

咱們來回顧一下。

一、使用帶有函數參數的new關鍵字定義Promise。 而後函數自己有兩個函數參數resolve和reject。

二、操做成功時應調用resolve函數。

三、操做失敗時應調用reject函數。

四、處理器then監控resolve函數。

五、處理器catch監控reject函數。

六、確保代碼的可讀性:) :)

這是可運行的示例。 若是您不熟悉,請練習。

var ApiCall = new Promise(function(resolve, reject) {
  
  var request = new XMLHttpRequest();
  request.open('GET', 'https://api.github.com/users/srebalaji');

  request.onload = function() {
    if (request.status == 200) {
      
      resolve(request.response);
    } else {
      reject(Error(request.statusText));
    }
  }

  request.send();
});

ApiCall
.then(function(x) {
  document.getElementById('response').innerHTML = x;
})
.catch(function(x) {
	document.getElementById('response').innerHTML = x;
})
複製代碼

但願你能理解這個例子。 它直截了當。

Async / Await

若是您瞭解Promises,那麼Async / Await很是簡單。 若是你沒有弄明白Promises,Async / Await能夠幫助你理解它。 也許你也能夠完全地躲開Promises。:)

Async

Async關鍵字使任何函數只返回promises。

例如,請看如下代碼

async function hello() {
 return "Hello Promise..!"
}
複製代碼

函數hello將返回一個promise。

上面的代碼至關於下面的代碼。

function hello() {
 return new Promise(function(resolve, reject) {
 // executor function body
 });
}
複製代碼

很是簡單是吧?

另一個例子:

async function hello(a, b) {
 if (a < b) {
  return "Greater";
 }
 else {
  return new Error("Not Greater");
 }
}
hello(14, 10)
.then(function(x) {
 console.log("Good..! " + x); 
})
.catch(function(x) {
 console.log("Oops..! " + x); 
})
輸出:
Oops..! Not Greater. 
// 若是你調用 hello(4, 10) 你會獲得 "Good..! Greater"
複製代碼

在上面的代碼中,咱們定義了一個async函數並返回了一些值或返回了一些錯誤。

若是要在async函數中返回一些值,則它等同於調用resolve函數。

若是經過使用'new'調用錯誤構造函數(即)返回一些錯誤,則它等同於reject函數。

不要忘記async函數將返回一個promise。 固然,你也能夠在async函數中調用resolve和reject函數。

讓咱們看看它是如何工做的。

async function Max(a, b) {
 if (a > b) {
  return Promise.resolve("Success");
 }
 else {
  return Promise.reject("Error");
 }
}
Max(4, 10)
.then(function(x) {
 console.log("Good " + x); 
})
.catch(function(x) {
 console.log("Oops " + x); 
});
輸出:
Oops Error
// 若是調用 Max(14, 10) 咱們會獲得 "Good Success" :)
複製代碼

Await

顧名思義,它使Javascript等到操做完成。 假設您正在使用await關鍵字發出API請求。 它使Javascript等待,直到您從端點得到響應。 而後它恢復執行。

好的..讓咱們走得更遠

Await只能在異步函數中使用。 它在異步功能以外不起做用

咱們來看一個例子吧

async function hello() {
 let response = await fetch('https://api.github.com/');
 // 上面一行從給定的API終端獲取響應
 return response;
}
hello()
.then(function(x) {
 console.log(x); 
});
...
...
輸出:
Response from the API.
複製代碼

在上面的代碼中,您能夠看到咱們在從API獲取響應時使用了await。

獲取操做可能須要幾秒鐘才能得到響應,直到獲取到響應,執行將暫停並稍後恢復。

請注意,await操做僅中止hello函數內的執行。 hello函數外的其他代碼不會受到影響。 執行在函數外部繼續。 當咱們獲得響應時,執行內部函數參數。

但願你明白了。

咱們來看一個例子

function getResponse() {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      resolve("Response from API. Executed after 5 secs");
    }, 5000);
  });
}

async function hello() {
  let response = await getResponse();
  return response;
}

hello()
  .then(function(x) {
    console.log(x);
  })
  .catch(function(x) {
    console.log(x);
  });
console.log("Im executed before getResponse()");
複製代碼

在上面的示例中,您能夠看到咱們對getResponse函數使用了await。 而且getResponse將在5秒後返回輸出或錯誤。 所以,在此以前,執行將暫停,而後返回響應。

讓咱們看一些實時的例子

function getResponse(url) {
	return new Promise(function(success, failure) {
  var request = new XMLHttpRequest();
	request.open('GET', url);
	
  request.onload = function() {
    if (request.status == 200) {
      return success(request.response);
    } else {
      return failure("Error in processing..!" + request.status);
    }
  }
  request.onerror = function() {
    return failure("Error in processing ");
  }
  request.send();
  });
}

function getUsername(response) {
  response = JSON.parse(response);
  return response["login"];
}

function makeUsernameCaps(name) {
	return new Promise(function(success, failure) {
  	// Let's assume it takes 3secs to make the username caps :) 
  	setTimeout(function() {
    success(name.toUpperCase());
    }, 3000)
  });
}
async function apiCall(url) {
  let response = await getResponse(url); 
  let username = await getUsername(response);
  let username_in_caps = await makeUsernameCaps(username);
  return username_in_caps;
}

apiCall("https://api.github.com/users/srebalaji")
.then(function(x) {
	console.log(x);
})
.catch(function(x) {
	console.log("Error - "+x);
});
複製代碼

在上面的例子中,您能夠看到咱們已經使用了多個await。 所以,對於每一個await, 程序中止執行,直到收到響應而後恢復。

在示例中嘗試使用一些無效網址。 您能夠看到引起錯誤。

async函數中的錯誤處理很是簡單。 若是在async函數內引起錯誤,或者在async函數中使用await調用的其餘函數內引起錯誤,則會調用reject函數。 簡單。

相關文章
相關標籤/搜索