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

原文戳這里

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

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

這篇文章的第一部分出現(xiàn)在這里。 我在那里介紹了一些有趣的功能:)

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

1、Promises

2、Async / Await

Promises

Promise是ES6中的一個(gè)有用功能。它們用于進(jìn)行異步操作,例如API請求,文件處理,下載圖像等。

那么,什么是異步? (繼續(xù),如果你已經(jīng)知道)

異步操作是需要一些時(shí)間才能完成的操作。

例如,假設(shè)您正在定義向服務(wù)器發(fā)出API請求的函數(shù)。該函數(shù)不會立即返回結(jié)果,因?yàn)閺姆?wù)器獲取響應(yīng)需要幾秒鐘。

因此,如果您正在調(diào)用該函數(shù)并將其值(即)返回的結(jié)果分配給某個(gè)變量,那么它將是未定義的。因?yàn)镴avascript不知道該函數(shù)正在處理一些異步操作。

那我們該如何處理呢?

讓我們先談?wù)勔恍v史。

在Promise之前,程序員習(xí)慣于定義回調(diào)?;卣{(diào)是Javascript中的常規(guī)函數(shù),它在異步操作完成時(shí)執(zhí)行。

例如,您定義了一個(gè)向服務(wù)器發(fā)出API請求的函數(shù)。然后你設(shè)置了一個(gè)回調(diào)函數(shù),它將在我們從服務(wù)器獲得響應(yīng)時(shí)執(zhí)行。

所以在上面的例子中,Javascript不會停止執(zhí)行,直到我們從API獲得響應(yīng)。我們已經(jīng)定義了一個(gè)函數(shù)(回調(diào)),它將在我們得到響應(yīng)后執(zhí)行。我想你明白了。

那么,Promise是什么?

Promise是有助于執(zhí)行異步操作的對象。

從技術(shù)上講,它們是表示異步操作完成的對象。 (如果你不明白,請繼續(xù)往下閱讀一會兒)

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

在Promise中有三種狀態(tài):

1、掛起:在這種狀態(tài)下,promise只是執(zhí)行異步操作。例如,它正在向服務(wù)器發(fā)出一些API請求或從cdn下載一些圖像。 從這個(gè)狀態(tài)Promise可以轉(zhuǎn)移到完成狀態(tài)或拒絕狀態(tài)

2、完成:如果Promise已達(dá)到此狀態(tài),則表示異步操作已完成,并且得到了輸出的結(jié)果。例如,我們有了來自API的響應(yīng)。

3、拒絕:如果Promise已達(dá)到此狀態(tài),則表示異步操作未成功,并且我們得到導(dǎo)致操作失敗的錯(cuò)誤。

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

const apiCall = new Promise(function(resolve, reject) {
 // 異步操作在這里定義..
});

通過使用new關(guān)鍵字創(chuàng)建構(gòu)造函數(shù)來定義Promise。 然后構(gòu)造函數(shù)將有一個(gè)函數(shù)(我們稱之為執(zhí)行函數(shù)。)

異步操作在執(zhí)行函數(shù)內(nèi)定義。

請注意,執(zhí)行函數(shù)有兩個(gè)參數(shù)resolve和reject。

第一個(gè)參數(shù)resolve實(shí)際上是一個(gè)函數(shù)。 它在執(zhí)行函數(shù)內(nèi)部調(diào)用,它表示異步操作成功,我們得到了結(jié)果。 resolve函數(shù)有助于Promise從掛起狀態(tài)轉(zhuǎn)為完成狀態(tài)。 希望你明白了。:)

像resolve一樣,reject也是一個(gè)函數(shù)。 它也在執(zhí)行函數(shù)內(nèi)部調(diào)用,它表示異步操作不成功,我們遇到了錯(cuò)誤。 reject函數(shù)有助于Promise從掛起狀態(tài)轉(zhuǎn)為拒絕狀態(tài)。:)

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

在上面的代碼中,您可以看到我們在執(zhí)行函數(shù)中完成了一些異步操作。 如果我們從服務(wù)器獲得響應(yīng),則調(diào)用resolve函數(shù)。 如果有錯(cuò)誤,則會使用錯(cuò)誤消息調(diào)用reject函數(shù)。

我們已經(jīng)完成了Promise。 讓我們看看如何執(zhí)行Promise并處理輸出。

// 調(diào)用promise.
apiCall

就是這樣。 結(jié)束了。 :) :)

開玩笑。 還沒結(jié)束。

在上面的代碼中,調(diào)用函數(shù)并執(zhí)行promise(即執(zhí)行函數(shù))。 然后根據(jù)輸出調(diào)用resolve或reject函數(shù)。

但是你可以看到我們沒有處理promise中返回的輸出。

例如,如果我們從API獲得響應(yīng),那么我們必須處理響應(yīng)。 或者如果我們得到錯(cuò)誤,我們需要正確處理它。

那我們該如何處理呢?

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

處理器是在某些事件發(fā)生時(shí)執(zhí)行的函數(shù),例如單擊按鈕,移動光標(biāo)等。

因此,當(dāng)resolve函數(shù)被調(diào)用或reject函數(shù)被調(diào)用時(shí),我們可以使用處理器來處理。

簡單。:)

我們來看一些代碼

// 調(diào)用promise,并使用handlers.
apiCall.then(function(x) {console.log(x); })

在上面的代碼中,我們將一個(gè)處理器then附加到promise。處理器then有一個(gè)函數(shù)參數(shù)。函數(shù)參數(shù)本身有一個(gè)參數(shù)x。

發(fā)生了什么事?

當(dāng)在promise內(nèi)調(diào)用resolve函數(shù)時(shí),處理器then執(zhí)行其函數(shù)參數(shù)。

我會再解釋一次。

處理器then監(jiān)聽resolve函數(shù)被調(diào)用時(shí)的事件。 因此,當(dāng)調(diào)用resolve函數(shù)時(shí),處理器then執(zhí)行其函數(shù)參數(shù)。

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

同樣,還有另一個(gè)處理器catch。

Catch監(jiān)聽reject函數(shù)。

Catch函數(shù)在reject函數(shù)被調(diào)用時(shí)執(zhí)行其函數(shù)參數(shù)。

apiCall.then(function(x) {console.log(x); }).catch(function(x) {console.log(x); })
// 假設(shè)這個(gè)請求沒有成功 (在promise中reject函數(shù)被調(diào)用. )
輸出:
The request is not successful

我想你明白了。

上面的代碼不太可讀。 所以讓我們嘗試重構(gòu)它。

apiCall
.then(function(x) {
 console.log(x); 
})
.catch(function(x) {
 console.log(x);
}) 

啊......現(xiàn)在可讀了。 大多數(shù)程序員都這樣寫。

好吧..所以我覺得你已經(jīng)走了很長的路。

我們來回顧一下。

1、使用帶有函數(shù)參數(shù)的new關(guān)鍵字定義Promise。 然后函數(shù)本身有兩個(gè)函數(shù)參數(shù)resolve和reject。

2、操作成功時(shí)應(yīng)調(diào)用resolve函數(shù)。

3、操作失敗時(shí)應(yīng)調(diào)用reject函數(shù)。

4、處理器then監(jiān)控resolve函數(shù)。

5、處理器catch監(jiān)控reject函數(shù)。

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

這是可運(yùn)行的示例。 如果您不熟悉,請練習(xí)。

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

希望你能理解這個(gè)例子。 它直截了當(dāng)。

Async / Await

如果您了解Promises,那么Async / Await非常簡單。 如果你沒有弄明白Promises,Async / Await可以幫助你理解它。 也許你也可以徹底地躲開Promises。:)

Async

Async關(guān)鍵字使任何函數(shù)只返回promises。

例如,請看以下代碼

async function hello() {
 return "Hello Promise..!"
}

函數(shù)hello將返回一個(gè)promise。

上面的代碼相當(dāng)于下面的代碼。

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

非常簡單是吧?

另外一個(gè)例子:

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. 
// 如果你調(diào)用 hello(4, 10) 你會得到 "Good..! Greater"

在上面的代碼中,我們定義了一個(gè)async函數(shù)并返回了一些值或返回了一些錯(cuò)誤。

如果要在async函數(shù)中返回一些值,則它等同于調(diào)用resolve函數(shù)。

如果通過使用'new'調(diào)用錯(cuò)誤構(gòu)造函數(shù)(即)返回一些錯(cuò)誤,則它等同于reject函數(shù)。

不要忘記async函數(shù)將返回一個(gè)promise。 當(dāng)然,你也可以在async函數(shù)中調(diào)用resolve和reject函數(shù)。

讓我們看看它是如何工作的。

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
// 如果調(diào)用 Max(14, 10) 我們會得到 "Good Success" :)

Await

顧名思義,它使Javascript等到操作完成。 假設(shè)您正在使用await關(guān)鍵字發(fā)出API請求。 它使Javascript等待,直到您從端點(diǎn)獲得響應(yīng)。 然后它恢復(fù)執(zhí)行。

好的..讓我們走得更遠(yuǎn)

Await只能在異步函數(shù)中使用。 它在異步功能之外不起作用

我們來看一個(gè)例子吧

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

在上面的代碼中,您可以看到我們在從API獲取響應(yīng)時(shí)使用了await。

獲取操作可能需要幾秒鐘才能獲得響應(yīng),直到獲取到響應(yīng),執(zhí)行將暫停并稍后恢復(fù)。

請注意,await操作僅停止hello函數(shù)內(nèi)的執(zhí)行。 hello函數(shù)外的其余代碼不會受到影響。 執(zhí)行在函數(shù)外部繼續(xù)。 當(dāng)我們得到響應(yīng)時(shí),執(zhí)行內(nèi)部函數(shù)參數(shù)。

希望你明白了。

我們來看一個(gè)例子

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函數(shù)使用了await。 并且getResponse將在5秒后返回輸出或錯(cuò)誤。 因此,在此之前,執(zhí)行將暫停,然后返回響應(yīng)。

讓我們看一些實(shí)時(shí)的例子

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

在上面的例子中,您可以看到我們已經(jīng)使用了多個(gè)await。 因此,對于每個(gè)await, 程序停止執(zhí)行,直到收到響應(yīng)然后恢復(fù)。

在示例中嘗試使用一些無效網(wǎng)址。 您可以看到引發(fā)錯(cuò)誤。

async函數(shù)中的錯(cuò)誤處理非常簡單。 如果在async函數(shù)內(nèi)引發(fā)錯(cuò)誤,或者在async函數(shù)中使用await調(diào)用的其他函數(shù)內(nèi)引發(fā)錯(cuò)誤,則會調(diào)用reject函數(shù)。 簡單。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 異步編程對JavaScript語言太重要。Javascript語言的執(zhí)行環(huán)境是“單線程”的,如果沒有異步編程,根本...
    呼呼哥閱讀 7,406評論 5 22
  • 弄懂js異步 講異步之前,我們必須掌握一個(gè)基礎(chǔ)知識-event-loop。 我們知道JavaScript的一大特點(diǎn)...
    DCbryant閱讀 2,886評論 0 5
  • Promise 對象 Promise 的含義 Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函...
    neromous閱讀 8,837評論 1 56
  • 其實(shí)夏天在小米的世界里,是和花兒一樣,冰涼可愛的。 一部分原因,是R·yBradbury的短篇小說中的一段描寫:“...
    七分秋色閱讀 483評論 0 1
  • 閑逸的夢醒了 我窺見瓶枝的蒼白 于是 在靜默的夜里 揉碎自己 就這樣魂歸泥土 尋回血脈根系 我知道郁結(jié)著怎樣的期待...
    襲瞬閱讀 246評論 2 1

友情鏈接更多精彩內(nèi)容