Vue 介面 promise + fetch + axios + async 和 await

2021-06-06 10:00:01

一、promise


1. 非同步

  • JS 是但執行緒,一次只能執行一個任務,任務執行完後才能執行下一個,它會「阻塞」其他任務,這個任務可稱為主執行緒

  • JS中常見的非同步呼叫
    ① 定時任務
    ② Ajax
    ③事件函數

  • 非同步模式可以一起執行多個任務,但是結果順序不確定,結果依賴於請求的這個程式的順序

  • 如許要規定結果列印的順序就需要函數巢狀,但是函數巢狀會形成回撥地獄,於是就需要用到 promise

2. Promise

Promise 是非同步程式設計的一種解決方案,Promise 是一個函數,函數也是物件,可以當作建構函式 new 出來

使用:

  • new 範例化 Promise 物件
  • 再定義處理的方案,自定義名 resolvereject 處理成功和失敗,這兩個引數都是方法可以直接呼叫
  • 然後通過 p.then 處理結果
 let p = new Promise(function (resolve, reject) {
     setTimeout(function () {
         let flag = false
         if (flag) {
             resolve(1);
         } else {
             reject(2);
         }
     }, 100)
 })
 
 p.then(function (data) {
     console.log(data);
 }, function (info) {
     console.log(info);
 })

3. 基於Promise傳送Ajax請求

1.返回promise範例物件

返回的該範例物件會呼叫下一個 then

2.返回普通值

如果 .then 返回的是一個普通值,那麼這個 then 會自動產生一個預設的 promise 物件,保證下一個 then 的使用,可以繼續進行鏈式操作

  <script type="text/javascript">
    /*
      基於Promise傳送Ajax請求
    */
    function queryData(url) {
     #   1.1 建立一個Promise範例
      var p = new Promise(function(resolve, reject){
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function(){
          if(xhr.readyState != 4) return;
          if(xhr.readyState == 4 && xhr.status == 200) {
            # 1.2 處理正常的情況
            resolve(xhr.responseText);
          }else{
            # 1.3 處理異常情況
            reject('伺服器錯誤');
          }
        };
        xhr.open('get', url);
        xhr.send(null);
      });
      return p;
    }
	# 注意:  這裡需要開啟一個服務 
    # 在then方法中,你也可以直接return資料而不是Promise物件,在後面的then中就可以接收到資料了
    queryData('http://localhost:3000/data')
      .then(function(data){
        console.log(data)
        #  1.4 想要繼續鏈式程式設計下去 需要 return  
        return queryData('http://localhost:3000/data1');
      })
      .then(function(data){
        console.log(data);
        return queryData('http://localhost:3000/data2');
      })
      .then(function(data){
        console.log(data)
      });
  </script>

4. Promise 基本API

實體方法

  • .then()
    得到非同步任務正確的結果

  • .catch()
    獲取異常資訊

  • .finally()
    成功與否都會執行(不是正式標準)

靜態方法(物件方法)

  • .all()
    並行處理多個非同步任務,所有任務都執行完了才能得到結果

Promise.all方法接受一個陣列作引數,陣列中的物件(p1、p2、p3)均為promise範例(如果不是一個promise,該項會被用Promise.resolve轉換為一個promise)。它的狀態由這三個promise範例決定

  • .race()
    並行處理多個非同步任務,只要有一個任務執行完了就能得到結果

Promise.race方法同樣接受一個陣列作引數。當p1, p2, p3中有一個範例的狀態發生改變(變為fulfilledrejected),p的狀態就跟著改變。並把第一個改變狀態的promise的返回值,傳給p的回撥函數

    var p1 = queryData('http://localhost:3000/a1');
    var p2 = queryData('http://localhost:3000/a2');
    var p3 = queryData('http://localhost:3000/a3');
     Promise.all([p1,p2,p3]).then(function(result){
       //   all 中的引數  [p1,p2,p3]   和 返回的結果一 一對應["HELLO TOM", "HELLO JERRY", "HELLO SPIKE"]
       console.log(result) //["HELLO TOM", "HELLO JERRY", "HELLO SPIKE"]
     })
    Promise.race([p1,p2,p3]).then(function(result){
      // 由於p1執行較快,Promise的then()將獲得結果'P1'。p2,p3仍在繼續執行,但執行結果將被丟棄。
      console.log(result) // "HELLO TOM"
    })


二、介面呼叫 fetch

  • Fetch API 是新的ajax解決方案
  • fetch不是ajax的進一步封裝,而是原生js,沒有使用XMLHttpRequest物件
  • fetch(url, options).then()
 // 先用 then 的方式得到 text 的資料
 fetch('/wwwww').then(data=>{
 // text 是 fetch 的一部分 返回值是一個 promise 範例物件 用於獲取後臺返回的資料
     return data.text()
 // 然後通過下一個 then 得到具體的資料
 }).then(ret=>{
     console.log(ret);
 })

fetch API 中的 HTTP 請求

  • fetch(url, options).then()
  • HTTP協定,它給我們提供了很多的方法,如POST,GET,DELETE,UPDATE,PATCH和PUT
    • 預設的是 GET 請求
    • 需要在 options 物件中 指定對應的 method method:請求使用的方法
    • post 和 普通 請求的時候 需要在options 中 設定 請求頭 headers 和 body
//Fetch API 呼叫介面傳遞引數
//1.1 GET引數傳遞 - 傳統URL  通過url  ? 的形式傳參 
fetch('http://localhost:3000/books?id=123', {
        // get 請求可以省略不寫 預設的是GET 
        method: 'get'
    })
    .then(function (data) {
        // 它返回一個Promise範例物件,用於獲取後臺返回的資料
        return data.text();
    }).then(function (data) {
        // 在這個then裡面我們能拿到最終的資料  
        console.log(data)
    });

//1.2  GET引數傳遞  restful形式的URL  通過/ 的形式傳遞引數  即  id = 456 和id後臺的設定有關   
fetch('http://localhost:3000/books/456', {
        // get 請求可以省略不寫 預設的是GET 
        method: 'get'
    })
    .then(function (data) {
        return data.text();
    }).then(function (data) {
        console.log(data)
    });

//2.1  DELETE請求方式引數傳遞      刪除id  是  id=789
fetch('http://localhost:3000/books/789', {
        method: 'delete'
    })
    .then(function (data) {
        return data.text();
    }).then(function (data) {
        console.log(data)
    });

//3 POST請求傳參
fetch('http://localhost:3000/books', {
        method: 'post',
        // 3.1  傳遞資料 
        body: 'uname=lisi&pwd=123',
        //  3.2  設定請求頭 
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded'
        }
    })
    .then(function (data) {
        return data.text();
    }).then(function (data) {
        console.log(data)
    });

// POST請求傳參
fetch('http://localhost:3000/books', {
        method: 'post',
        body: JSON.stringify({
            uname: '張三',
            pwd: '456'
        }),
        headers: {
            'Content-Type': 'application/json'
        }
    })
    .then(function (data) {
        return data.text();
    }).then(function (data) {
        console.log(data)
    });

// PUT請求傳參     修改id 是 123 的 
fetch('http://localhost:3000/books/123', {
        method: 'put',
        body: JSON.stringify({
            uname: '張三',
            pwd: '789'
        }),
        headers: {
            'Content-Type': 'application/json'
        }
    })
    .then(function (data) {
        return data.text();
    }).then(function (data) {
        console.log(data)
    });

fetchAPI 中 響應格式

  • text() 將返回體處理成字串型別
  • json() 返回結果和 JSON.parse(responseText) 一樣
  • 用fetch來獲取資料,如果響應正常返回,我們首先看到的是一個response物件,其中包括返回的一堆原始位元組,這些位元組需要在收到後,需要我們通過呼叫方法將其轉換為相應格式的資料,比如JSONBLOB或者TEXT等等
//Fetch響應結果的資料格式
fetch('http://localhost:3000/json').then(function (data) {
    // return data.json();
    //  將獲取到的資料使用 json 轉換物件
    return data.text();
}).then(function (data) {
    // console.log(data.uname)
    // console.log(typeof data)
    var obj = JSON.parse(data);
    console.log(obj.uname, obj.age, obj.gender)
})


三、介面呼叫 axios

  • 基於promise用於瀏覽器和node.js的http使用者端
  • 支援瀏覽器和node.js
  • 支援promise
  • 能攔截請求和響應
  • 自動轉換JSON資料
  • 能轉換請求和響應資料

1. axios 基礎用法

 axios.get('/www')
 .then(ret=>{
     // data 的名字是固定的,它用於獲取後臺響應的資料
     console.log(ret.data);
 })

查詢資料 get
刪除資料 delete

  • 通過傳統的url 以 ? 的形式傳遞引數
  • restful 形式傳遞引數
  • 通過params 形式傳遞引數

新增資料 post
修改資料 put

  • 通過選項傳遞引數
  • 通過 URLSearchParams 傳遞引數
//# 1. 傳送get 請求
 axios.get('http://localhost:3000/adata').then(function (ret) {
     //#拿到 ret 是一個物件 所有的物件都存在 ret 的data 屬性裡面
     // 注意data屬性是固定的用法,用於獲取後臺的實際資料
     // console.log(ret.data)
     console.log(ret)
 })
 //# 2. get 請求傳遞引數# 2.1 通過傳統的url 以 ? 的形式傳遞引數
 axios.get('http://localhost:3000/axios?id=123').then(function (ret) {
     console.log(ret.data)
 })
 //# 2.2 restful 形式傳遞引數
 axios.get('http://localhost:3000/axios/123').then(function (ret) {
     console.log(ret.data)
 })
 //# 2.3 通過params 形式傳遞引數
 axios.get('http://localhost:3000/axios', {
     params: {
         id: 789
     }
 }).then(function (ret) {
     console.log(ret.data)
 })
 //#3 axios delete 請求傳參     傳參的形式和 get 請求一樣
 axios.delete('http://localhost:3000/axios', {
     params: {
         id: 111
     }
 }).then(function (ret) {
     console.log(ret.data)
 })
 //# 4 axios 的 post 請求# 4.1 通過選項傳遞引數
 axios.post('http://localhost:3000/axios', {
     uname: 'lisi',
     pwd: 123
 }).then(function (ret) {
     console.log(ret.data)
 })
 //# 4.2 通過 URLSearchParams 傳遞引數
 var params = new URLSearchParams();
 params.append('uname', 'zhangsan');
 params.append('pwd', '111');
 axios.post('http://localhost:3000/axios', params).then(function (ret) {
     console.log(ret.data)
 })
 //#5  axios put 請求傳參   和 post 請求一樣 
 axios.put('http://localhost:3000/axios/123', {
     uname: 'lisi',
     pwd: 123
 }).then(function (ret) {
     console.log(ret.data)
 })

2. axios 全域性設定

//  設定公共的預設地址
axios.defaults.baseURL = 'https://api.example.com';
//  設定 超時時間
axios.defaults.timeout = 2500;
//  設定公共的請求頭
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
// 設定公共的 post 的 Content-Type
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

3. axios 攔截器

請求攔截器

  • 請求攔截器的作用是在請求傳送前進行一些操作
  • 例如在每個請求體里加上token,統一做了處理如果以後要改也非常容易

響應攔截器

  • 響應攔截器的作用是在接收到響應後進行一些操作
  • 例如在伺服器返回登入狀態失效,需要重新登入的時候,跳轉到登入頁
 //# 1. 請求攔截器 
 axios.interceptors.request.use(function (config) {
     console.log(config.url)
 //# 1.1  任何請求都會經過這一步   在傳送請求之前做些什麼   
     config.headers.mytoken = 'nihao';
 //# 1.2  這裡一定要return   否則設定不成功  
     return config;
 }, function (err) {
 //#1.3 對請求錯誤做點什麼    
     console.log(err)
 })
 //#2. 響應攔截器 
 axios.interceptors.response.use(function (res) {
 //#2.1  在接收響應做些什麼  
     var data = res.data;
     return data;
 }, function (err) {
 //#2.2 對響應錯誤做點什麼  
     console.log(err)
 })


四、async 和 await

async作為一個關鍵字放到函數前面

  • 任何一個async函數都會隱式返回一個promise

await 關鍵字只能在使用 async 定義的函數中使用

  • ​ await後面可以直接跟一個 Promise範例物件
  • ​ await函數不能單獨使用

async/await 讓非同步程式碼看起來、表現起來更像同步程式碼

 //# 1.  async 基礎用法
 //# 1.1 async作為一個關鍵字放到函數前面
 async function queryData() {
 //# 1.2 await關鍵字只能在使用async定義的函數中使用      await後面可以直接跟一個 Promise範例物件
     var ret = await new Promise(function (resolve, reject) {
         setTimeout(function () {
             resolve('nihao')
         }, 1000);
     })
 // console.log(ret.data)
     return ret;
 }
 //# 1.3 任何一個async函數都會隱式返回一個promise   我們可以使用then 進行鏈式程式設計
 queryData().then(function (data) {
     console.log(data)
 })
 //#2.  async    函數處理多個非同步函數
 axios.defaults.baseURL = 'http://localhost:3000';
 async function queryData() {
 //# 2.1  新增await之後 當前的await 返回結果之後才會執行後面的程式碼   
     var info = await axios.get('async1');
 //#2.2  讓非同步程式碼看起來、表現起來更像同步程式碼
     var ret = await axios.get('async2?info=' + info.data);
     return ret.data;
 }
 queryData().then(function (data) {
     console.log(data)
 })