JavaScript 之 異步請求

1、

一、異步(async)

異步,它的孿生兄弟--同步(Synchronous),"同步模式"就是上一段的模式,後一個任務等待前一個任務結束,而後再執行,程序的執行順序與任務的排列順序是一致的、同步的.javascript

"異步模式"則徹底不一樣,每個任務有一個或多個回調函數(callback),前一個任務結束後,不是執行後一個任務,而是執行回調函數,後一個任務則是不等前一個任務結束就執行,因此程序的執行順序與任務的排列順序是不一致的、異步的。 "異步模式"很是重要。在瀏覽器端,耗時很長的操做都應該異步執行,避免瀏覽器失去響應,最好的例子就是Ajax操做。就如今來講應該沒有什麼後臺服務器仍是同步操做了...html

用最直觀的代碼來體現:前端

 1 <body>
 2 <button id="Button">展現異步操做</button>
 3 <script>
 4 var Button=document.getElementById('Button');
 5 Button.onclick=function(){
 6 alert('展現異步操做--a');
 7 }
 8 alert('展現異步操做--b');
 9 </script>
10 </body>

這個簡單的例子就體現出了異步和同步的區別了:java

咱們日常寫的代碼,都是從上到下來執行的,通常上面的語句尚未執行結束的狀況下,下面的語句是不會執行的,可是這段代碼咱們很容易測試出:先彈出b窗口,當你點擊按鈕的時候纔開始彈出a窗口。 這就是典型的異步操做,不用等把上面的語句所有執行完纔開始執行下面的語句。jquery

 

二、Promise 

Javascript 採用回調函數(callback)來處理異步編程。從同步編程到異步回調編程有一個適應的過程,可是若是出現多層回調嵌套,也就是咱們常說的厄運的回調金字塔(Pyramid of Doom),絕對是一種糟糕的編程體驗。因而便有了 CommonJS 的 Promises/A 規範,用於解決回調金字塔問題。本文先介紹 Promises 相關規範,而後再經過解讀一個迷你的 Promises 以加深理解。程序員

什麼是 Promise

一個 Promise 對象表明一個目前還不可用,可是在將來的某個時間點能夠被解析的值。它容許你以一種同步的方式編寫異步代碼。例如,若是你想要使用 Promise API 異步調用一個遠程的服務器,你須要建立一個表明數據將會在將來由 Web 服務返回的 Promise 對象。惟一的問題是目前數據還不可用。當請求完成並從服務器返回時數據將變爲可用數據。在此期間,Promise 對象將扮演一個真實數據的代理角色。接下來,你能夠在 Promise 對象上綁定一個回調函數,一旦真實數據變得可用這個回調函數將會被調用。ajax

Promise 對象曾經以多種形式存在於許多語言中。算法

去除厄運的回調金字塔(Pyramid of Doom)

Javascript 中最多見的反模式作法是回調內部再嵌套回調。編程

 1 // 回調金字塔
 2 asyncOperation(function(data){
 3   // 處理 `data`
 4   anotherAsync(function(data2){
 5       // 處理 `data2`
 6       yetAnotherAsync(function(){
 7           // 完成
 8       });
 9   });
10 });

引入 Promises 以後的代碼api

 1 promiseSomething()
 2 .then(function(data){
 3     // 處理 `data`
 4     return anotherAsync();
 5 })
 6 .then(function(data2){
 7     // 處理 `data2`
 8     return yetAnotherAsync();
 9 })
10 .then(function(){
11     // 完成
12 });

Promises 將嵌套的 callback,改形成一系列的.then的連綴調用,去除了層層縮進的糟糕代碼風格。Promises 不是一種解決具體問題的算法,而已一種更好的代碼組織模式。接受新的組織模式同時,也逐漸以全新的視角來理解異步調用。

 

三、Fetch API

Fetch API 提供了一個獲取資源的接口(包括跨域)。任何使用過 XMLHttpRequest 的人都能輕鬆上手,但新的API提供了更強大和靈活的功能集。

Fetch 提供了對 Request 和 Response (以及其餘與網絡請求有關的)對象的通用定義。使之從此能夠被使用到更多地應用場景中:不管是service workers、Cache API、又或者是其餘處理請求和響應的方式,甚至是任何一種須要你本身在程序中生成響應的方式。

它還提供了一種定義,將 CORS 和 HTTP 原生的頭信息結合起來,取代了原來那種分離的定義。

 

四、閉包 (closure)

閉包和詞法做用域很是相近。一個關於閉包如何工做的更好或者更實際的例子就是返回一個函數的引用。

咱們能夠返回域中的東西,使得它們能夠被其父域所用。

當你在函數裏聲明一個變量時,你只能在函數內訪問。這些變量的做用域就被限制在函數裏了。

若是你在一個函數內又定義了內部函數,那麼這個內部函數就被稱做閉包。它仍能夠訪問外部函數的做用域。

2、

在開發過程當中,咱們向服務端發送請求,通常會使用三種方式, XMLHttpRequest(XHR),Fetch ,jQuery實現的AJAX。
其中, XMLHttpRequest(XHR)和Fetch是瀏覽器的原生API,jquery的ajax實際上是封裝了XHR。
這裏咱們主要比較一下Fetch與XHR在異步請求中的使用示例。

XMLHttpRequest

 1 var xhr;
 2 if (window.XMLHttpRequest) {  // Mozilla, Safari...
 3    xhr = new XMLHttpRequest();
 4 } else if (window.ActiveXObject) { // IE
 5    try {
 6      xhr = new ActiveXObject('Msxml2.XMLHTTP');
 7    } catch (e) {
 8      try {
 9        xhr = new ActiveXObject('Microsoft.XMLHTTP');
10      } catch (e) {}
11    }
12 }
13 if (xhr) {
14    xhr.onreadystatechange = onReadyStateChange;
15    xhr.open('POST', '/api', true);
16    // 設置 Content-Type 爲 application/x-www-form-urlencoded
17    // 以表單的形式傳遞數據
18    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
19    xhr.send('username=admin&password=root');
20 }
21 
22 // onreadystatechange 方法
23 function onReadyStateChange() {
24    // 該函數會被調用四次
25    console.log(xhr.readyState);
26    if (xhr.readyState === 4) {
27       // everything is good, the response is received
28       if (xhr.status === 200) {
29          console.log(xhr.responseText);
30       } else {
31          console.log('There was a problem with the request.');
32       }
33    } else {
34       // still not ready
35       console.log('still not ready...');
36    }
37 }

從上邊的代碼能夠看出,XMLHttpRequest 是一個很是粗糙的API,不符合關注分離的原則,配置和調用方式很是混亂,前端程序員們不只要作各個瀏覽器的兼容性,還飽受回調地獄的折磨,這顯然不是一個好的選擇。

Fetch

1 fetch(...).then(fun2)
2           .then(fun3) //各依賴有序執行
3           .....
4           .catch(fun)

從上邊的代碼能夠看出,fetch解決了回調地獄問題,使用簡便,雖然仍是有Callback的影子,可是看起來舒服多了。

Fetch 優勢:

  1. 語法簡潔,更加語義化
  2. 基於標準 Promise 實現,支持 async/await
  3. 同構方便,使用isomorphic-fetch
Fetch和xhr的不一樣
          一、fetch雖然底層,可是仍是缺乏一些經常使用xhr有的方法,好比可以取消請求(abort)方法
          二、fetch在服務器返回4xx、5xx時是不會拋出錯誤的,這裏須要手動經過,經過response中的ok字段和status字段來判斷

---------------------
部份內容摘自網絡:
https://www.jianshu.com/p/35123b048e5e
http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html
https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch
相關文章
相關標籤/搜索