第五節: 前后端交互之Promise用法和Fetch用法


一. Promise相關

1.說明

  主要解決異步深層嵌套的問題,promise 提供了簡潔的API 使得異步操作更加容易 。

2.入門使用

  我們使用new來構建一個Promise Promise的構造函數接收一個參數,是函數,並且傳入兩個參數:resolve,reject,分別表示異步操作執行成功后的回調函數和異步操作執行失敗后的回調函數。

    var p = new Promise(function(resolve, reject) {
          // 這里用於實現異步任務
          setTimeout(function() {
               var flag = false;
               if (flag) {
                     // 正常情況
                      resolve('hello');
               } else {
                     // 異常情況
                      reject('出錯了');
         }
         }, 100);
   });
   p.then(function(data) {
       console.log(data)
   }, function(info) {
       console.log(info)
   });

補充:回調地獄問題解決? 

3. 基本Api

  then-catch-finally, 其中then-catch等價於 then(fun1,fun2),fun2相當於catch。

代碼:

 1      function foo() {
 2          return new Promise(function(resolve, reject) {
 3               setTimeout(function() {
 4                        // resolve(123);
 5                        reject('error');
 6                }, 100);
 7         })
 8      }
 9                         // foo()
10                         //   .then(function(data){
11                         //     console.log(data)
12                         //   })
13                         //   .catch(function(data){
14                         //     console.log(data)
15                         //   })
16                         //   .finally(function(){
17                         //     console.log('finished')
18                         //   });
19 
20                         // --------------------------
21                         // 兩種寫法是等效的
22                         foo()
23                             .then(function(data) {
24                                 console.log(data)
25                             }, function(data) {
26                                 console.log(data)
27                             })
28                             .finally(function() {
29                                 console.log('finished')
30                             });

4.對象方法

(1). all:方法接受一個數組作參數,數組中的對象(p1、p2、p3)均為promise實例(如果不是一個promise,該項會被用 Promise.resolve 轉換為一個promise)。它的狀態由這三個promise實例決定。

(2). race:Promise.race 方法同樣接受一個數組作參數。當p1, p2, p3中有一個實例的狀態發生改變(變為 fulfilled或 rejected ),p的狀態就跟着改變。並把第一個改變狀態的promise的返回值傳給p的回調函數。

代碼分享:

 

 

二. Fetch用法

補充:

參考 API文檔:https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch

其它參考:https://www.cnblogs.com/wonyun/p/fetch_polyfill_timeout_jsonp_cookie_progress.html

用到的服務端接口方法:

 1     [Route("api/[controller]/[action]")]
 2     [ApiController]
 3     public class FirstController : ControllerBase
 4     {
 5 
 6         /******************************************下面是測試Get請求的相關方法***************************************************/
 7 
 8         #region 下面是測試Get請求的相關方法
 9         [HttpGet]
10         public string GetInfor1(string userName, string pwd)
11         {
12             return $"{userName}+{pwd}";
13         }
14 
15         [HttpGet]
16         public string GetInfor2([FromQuery]UserInfor model)
17         {
18             return $"{model.userName}+{model.pwd}";
19         }
20         [HttpGet]
21         //加上[FromQuery]也報錯
22         public string GetInfor3([FromQuery]dynamic model)
23         {
24             return $"{model.userName}+{model.pwd}";
25         }
26 
27         #endregion
28 
29     }
30     [Route("api/[controller]/[action]")]
31     [ApiController]
32     public class ThirdController : Controller
33     {
34        [HttpGet]
35         public IActionResult GetInfor4(string userName, string pwd)
36         {
37             return Json(new
38             {
39                 userName,
40                 pwd
41             });
42         }
43     }
View Code

1.簡介

  Fetch API是新的ajax解決方案 Fetch會返回Promise, fetch不是ajax的進一步封裝,而是原生js,不需要引入任何庫,沒有使用XMLHttpRequest對象。

2.基本用法

  (1).通用格式 fetch().then().then().catch() ,第一個then處理返回類型,在第二個then里才拿到返回值,里面的function可以簡化寫法。

  (2).默認是get請求。

代碼分享:

                        //默認是Get請求的
                        fetch("https://localhost:44387/api/First/GetInfor1?userName=ypf&pwd=123456").then(function(data) {
                            return data.text();
                        }).then(function(data) {
                            console.log(data);
                        });

                        //簡潔寫法:
                        fetch("https://localhost:44387/api/First/GetInfor1?userName=ypf&pwd=123456").then(data => data.text()).then(
                            data => {
                                console.log(data);
                        });

  (3).Post請求同樣分兩種,表單提交和json提交,需要在headers設置 Content-Type類型。

代碼如下:

 1                        //表單提交
 2                         fetch('https://localhost:44387/api/First/Login3', {
 3                                 method: 'post',
 4                                 body: 'userName=ypf&pwd=123456',
 5                                 headers: {
 6                                     'Content-Type': 'application/x-www-form-urlencoded'
 7                                 },
 8                             })
 9                             .then(function(data) {
10                                 return data.text();
11                             }).then(function(data) {
12                                 console.log(data)
13                             });
14                       //JSON提交
15                         fetch('https://localhost:44387/api/First/Login2', {
16                                 method: 'post',
17                                 body: JSON.stringify({
18                                     userName: "admin",
19                                     pwd: "123456"
20                                 }),
21                                 headers: {
22                                     'Content-Type': 'application/json',
23                                     'token': 'dsfsdf',
24                                 }
25                             })
26                             .then(function(data) {
27                                 return data.text();
28                             }).then(function(data) {
29                                 console.log(data)
30                             });

  (4).如何處理請求錯誤?

  根據上面的通用格式,肯定是在catch中處理,但是fetch返回的promise對於404、415、500這些錯誤是獲取不到,進入不到catch,catch僅能獲取由於網絡延遲錯誤,所以這里需要再次封裝一下,獲取這些狀態,進行throw拋出,讓其進入catch即可。 案例如下:

 1                         //處理非網絡錯誤導致的 錯誤
 2                         fetch("https://localhost:44387/api/First/GetInfor3?userName=ypf&pwd=123456").then(function(response) {
 3                             console.log(response);
 4                             if (response.status >= 200 && response.status < 300) {
 5                                 return response;
 6                             }
 7                             const error = new Error(response.statusText);
 8                             error.response = response;
 9                             throw error; //檢測到報錯會進入到catch中
10                         }).then(function(data) {
11                             return data.text();
12                         }).then(function(data) {
13                             console.log(data);
14                         }).catch(function(error) {
15                             console.log(error.response.status + '--' + error.response.statusText);
16                             console.log('There has been a problem with your fetch operation: ', error.message);
17                         });

PS: put和delete用法和post類似,這里不再演示。

3.返回數據的處理

  (1).text():返回的數據是字符串,如果服務器端返回的是json,而這里用text接收,再下一個then里使用的時候需要轉換一下,JSON.parse(data)。

  (2).json():返回的數據直接轉換成JOSN,后面直接使用即可。

  (3).其它:arrayBuffer()、blob()、formData()。

 代碼分享:

 1   //返回的數據是JSON格式的, 如果用data.text()接收,需要JSON.parse(data);轉換一下
 2                         fetch("https://localhost:44387/api/Third/GetInfor4?userName=ypf&pwd=123456").then(function(data) {
 3                             return data.text();
 4                         }).then(function(data) {
 5                             var myData = JSON.parse(data);
 6                             console.log(myData.userName + '--' + myData.pwd);
 7                         })
 8 //返回的數據是JSON格式的, 如果用data.json()接收,直接使用即可
 9                         fetch("https://localhost:44387/api/Third/GetInfor4?userName=ypf&pwd=123456").then(function(data) {
10                             return data.json();
11                         }).then(function(data) {
12                             console.log(data.userName + '--' + data.pwd);
13                         })

4.其它參數詳細配置

  (1).method: 請求使用的方法,如 GET、POST, 默認是Get。

  (2).headers: 請求的頭信息,比如可以在里面設置Token、設置content-type類型。

  (3).credentials: 請求的 credentials,如 omit、same-origin 或者 include。為了在當前域名內自動發送 cookie , 必須提供這個選項, 從 Chrome 50 開始,這個屬性也可以接受 FederatedCredential 實例或是一個 PasswordCredential 實例。

  (4). mode: 請求的模式,如 cors、 no-cors 或者 same-origin(默認值)。

  (5).body: 請求的 body 信息:可能是一個 Blob、BufferSource、FormData、URLSearchParams 或者 USVString 對象。注意 GET 或 HEAD 方法的請求不能包含 body 信息。

  (6).cache: 請求的 cache 模式: default 、 no-store 、 reload 、 no-cache 、 force-cache 或者 only-if-cached 。

  (7).redirect: 可用的 redirect 模式: follow (自動重定向), error (如果產生重定向將自動終止並且拋出一個錯誤), 或者 manual (手動處理重定向). 在Chrome中,Chrome 47之前的默認值是 follow,從 Chrome 47開始是 manual。

  (8).referrer: 一個 USVString 可以是 no-referrer、client或一個 URL。默認是 client。

  (9).referrerPolicy: 指定了HTTP頭部referer字段的值。可能為以下值之一: no-referrer、 no-referrer-when-downgrade、 origin、 origin-when-cross-origin、 unsafe-url 。

  (10).integrity: 包括請求的 subresource integrity 值 ( 例如: sha256-BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=)。

分析總結:

  (1). fetch發送請求默認是不發送cookie的,不管是同域還是跨域;那么問題就來了,對於那些需要權限驗證的請求就可能無法正常獲取數據,這時可以配置其credentials項,其有3個值:

    A.omit: 默認值,忽略cookie的發送

    B.same-origin: 表示cookie只能同域發送,不能跨域發送

    C.include: cookie既可以同域發送,也可以跨域發送

  PS:fetch默認對服務端通過Set-Cookie頭設置的cookie也會忽略,若想選擇接受來自服務端的cookie信息,也必須要配置credentials選項;

  (2). fetch不支持超時timeout處理

  (3). fetch不支持JSONP。目前比較成熟的開源JSONP實現fetch-jsonp給我們提供了解決方案,想了解可以自行前往。(https://github.com/camsong/fetch-jsonp)

  (4). 與XHR2一樣,fetch也是支持跨域請求的,只不過其跨域請求做法與XHR2一樣,需要客戶端與服務端支持;另外,fetch還支持一種跨域,不需要服務器支持的形式,具體可以通過其mode的配置項來說明。

    A.same-origin:該模式是不允許跨域的,它需要遵守同源策略,否則瀏覽器會返回一個error告知不能跨域;其對應的response type為basic。

    B.cors: 該模式支持跨域請求,顧名思義它是以CORS的形式跨域;當然該模式也可以同域請求不需要后端額外的CORS支持;其對應的response type為cors。

    C.no-cors: 該模式用於跨域請求但是服務器不帶CORS響應頭,也就是服務端不支持CORS;這也是fetch的特殊跨域請求方式;其對應的response type為opaque。(重點!!!)

  特別注意:no-cors該模式允許瀏覽器發送本次跨域請求,但是不能訪問響應返回的內容(能訪問通接口,但是不能拿到返回值),這也是其response type為opaque透明的原因。

 1                        //特殊跨域不需要服務器端進行設置,能訪問通,但是拿不到響應結果
 2                         fetch('https://localhost:44387/api/First/Login3', {
 3                                 method: 'post',
 4                                 body: 'userName=ypf&pwd=123456',
 5                                 headers: {
 6                                     'Content-Type': 'application/x-www-form-urlencoded'
 7                                 },
 8                                 mode: 'no-cors'
 9                             })
10                             .then(function(data) {
11                                 return data.text();
12                             }).then(function(data) {
13                                 console.log(data)
14                             });

 

 

 

 

 

!

  • 作       者 : Yaopengfei(姚鵬飛)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 聲     明1 : 如有錯誤,歡迎討論,請勿謾罵^_^。
  • 聲     明2 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權利。
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM