05 . Vue前端互動,fetch,axios,以asyncawait方式呼叫介面使用及案例

youmen發表於2020-11-19

目標

/*
		1. 說出什麼是前後端互動模式
		2. 說出Promise的相關概念和用法
		3. 使用fetch進行介面呼叫
		4. 使用axios進行介面呼叫
		5. 使用asynnc/await方式呼叫介面
		6. 基於後臺介面實現案例
*/

前後端互動模式

介面呼叫方式
/*
		原生ajax
		基於jQuery的ajax
		fetch
		axios
*/
傳統形式的URL
/*
		格式: schema://host:port/path?query#fragment
		
				1. schema: 協議. 例如http,https,ftp等
				2. host:  域名或者IP地址
				3. port:  埠,http預設埠80,可以省略
				4. path:  路徑,例如/abc/a/b/c
				5. query:  查詢引數uname=list&age=12
				6. fragment: 錨點(雜湊Hash),用於定位頁面某個位置
*/
Restful形式的URL
/*
			HTTP請求方式
					1. GET		查詢
					2. POST		新增
					3. PUT		修改
					4. DELETE 刪除
*/

Promise

傳統js非同步呼叫

非同步呼叫分析

/*
		1. 定時任務
		2. Ajax
		3. 事件函式
*/

多次非同步呼叫的依賴分析

/*
		多次非同步呼叫的結果順序不確定
		非同步呼叫結果如果存在依賴需要巢狀
*/

Example(傳統ajax)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>

<body>
<div id="app">

</div>

<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
    var vm = new Vue({
        el: '#app',
        data: {},
        methods: {}
    })
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<div>前後端互動</div>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript">
    /*
        前後端互動,非同步程式設計與Promise概述
     */

    var ret = '---'

    $.ajax({
        url: 'http://localhost:3000/data',
        success: function (data) {
            ret = data
            console.log(ret)
        }
    });
    console.log(ret)
</script>

</body>
</html>
Promise概述

Promise是非同步程式設計的一種解決方案,從語法上講,Promise是一個物件,從他可以獲取非同步操作的資訊.

Promise好處
/*
		使用Promise主要有以下好處:
			可以避免多層非同步呼叫巢狀問題(回撥地獄)
			Promise物件提供了簡介的API,使得控制非同步操作更加容易
*/
Promise使用
/*
		基本用法
    	例項化Promise物件,建構函式中傳遞函式,該函式用於處理非同步任務.
    	resolv和reject兩個引數用於處理成功和失敗兩種情況,並通過p.then獲取處理結果.
*/

var p = new Promise(function(resolve,reject){
  // 成功時呼叫 resolve()
  // 失敗時呼叫 reject()
  p.then(function(ret){
    	// 從resolve得到正常結果
  },function(ret){
      // 從reject得到錯誤資訊
  });
});

Example1

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>

<body>
<div id="app">

</div>

<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
    var vm = new Vue({
        el: '#app',
        data: {},
        methods: {}
    })
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<div>前後端互動</div>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript">
    /*
        Promise基本使用
     */
    var p = new Promise(function (resolve, reject) {
        // 這裡用於實現非同步任務
        setTimeout(function () {
            var flag = false;
            if (flag) {
                // 正常情況
                resolve('hello');
            } else {
                // 異常情況
                reject('500');
            }
        }, 100);
    });
    p.then(function (data) {
        console.log(data)
    }, function (info) {
        console.log(info)
    })

</script>

</body>
</html>
處理原生Ajax
function queryData(){
	return new Promise(function(resolve,reject){
		var xhr - new XMLHttpRequest();
		xhr.cnreadystatechange = function(){
			if(xhr.readyState != 4) return;
			if(xhr.status == 200){
				resolve(xhr.responseText)
			}else{
				reject('出錯了');
				}
			}
			xhr.open('get','/data');
			xhr.send(null);
			})
}

處理多次Ajax請求

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>

<body>
<div id="app">

</div>

<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
    var vm = new Vue({
        el: '#app',
        data: {},
        methods: {}
    })
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<div>前後端互動</div>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript">
    /*
        基於Promise傳送Ajax請求
     */
    function queryData(url) {
        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) {
                    // 處理正常情況
                    resolve(xhr.responseText);
                } else {
                    // 處理異常情況
                    reject('伺服器錯誤');
                }
            };
            xhr.open('get', url);
            xhr.send(null);
        });
        return p;
    }

    // queryData('http://localhost:3000/data')
    //     .then(function(data){
    //         console.log(data)
    //     },function(info){
    //         console.log(info)
    //     });

    // 傳送多個Ajax請求並且保證順序
    queryData('http://localhost:3000/data')
        .then(function (data) {
            console.log(data)
            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>

</body>
</html>
then引數中的函式返回值
/*
		1. 返回Promise例項物件
				返回的該例項物件會呼叫下一個then
				
		2. 返回普通值
				返回的普通值會直接傳遞給下一個then,通過then引數中函式的引數接受該值
*/

Example

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  
  <script type="text/javascript">
    /*
      then引數中的函式返回值
    */
    function queryData(url) {
      return new Promise(function(resolve, reject){
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function(){
          if(xhr.readyState != 4) return;
          if(xhr.readyState == 4 && xhr.status == 200) {
            // 處理正常的情況
            resolve(xhr.responseText);
          }else{
            // 處理異常情況
            reject('伺服器錯誤');
          }
        };
        xhr.open('get', url);
        xhr.send(null);
      });
    }
    queryData('http://localhost:3000/data')
      .then(function(data){
        return queryData('http://localhost:3000/data1');
      })
      .then(function(data){
        return new Promise(function(resolve, reject){
          setTimeout(function(){
            resolve(123);
          },1000)
        });
      })
      .then(function(data){
        return 'hello';
      })
      .then(function(data){
        console.log(data)
      })

  </script>
</body>
</html>
Promise常用API
/*
		例項方法
			p.then() 得到非同步任務的正確結果
			p.catch() 獲取異常資訊
			p.finally()  成功與否都會執行(尚且不是正式標準)
			
		queryData()
			.then(function(data){
				console.log(data);
			})
			
			.catch(function(data){
				console.log(data);
			})
			
			.finally(function(){
				console.log('finished');
			});
*/

Example1

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  
  <script type="text/javascript">
    /*
      Promise常用API-例項方法
    */
    // console.dir(Promise);
    function foo() {
      return new Promise(function(resolve, reject){
        setTimeout(function(){
          // resolve(123);
          reject('error');
        }, 100);
      })
    }
    // foo()
    //   .then(function(data){
    //     console.log(data)
    //   })
    //   .catch(function(data){
    //     console.log(data)
    //   })
    //   .finally(function(){
    //     console.log('finished')
    //   });

    // --------------------------
    // 兩種寫法是等效的
    foo()
      .then(function(data){
        console.log(data)
      },function(data){
        console.log(data)
      })
      .finally(function(){
        console.log('finished')
      });
  </script>
</body>
</html>

物件方法

/*
		Promise.all()  併發處理多個非同步任務,所有任務都執行成功才能得到結果
		Promise.race()  併發處理多個非同步任務,只要有一個任務完成就能得到結果
*/

Promise.all([p1,p2,p3]).then((result) =>{
  console.log(result)
})

Promise.race([p1,p2,p3]).then((result) =>{
  console.log(result)
})

Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>

<script type="text/javascript">
    /*
      Promise常用API-物件方法
    */
    // console.dir(Promise)
    function queryData(url) {
        return new Promise(function (resolve, reject) {
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function () {
                if (xhr.readyState != 4) return;
                if (xhr.readyState == 4 && xhr.status == 200) {
                    // 處理正常的情況
                    resolve(xhr.responseText);
                } else {
                    // 處理異常情況
                    reject('伺服器錯誤');
                }
            };
            xhr.open('get', url);
            xhr.send(null);
        });
    }

    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){
    //   console.log(result)
    // })
    Promise.race([p1, p2, p3]).then(function (result) {
        console.log(result)
    })
</script>
</body>
</html>

fetch請求元件

fetch

XMLHttpRequest是一個設計粗糙的API, 配置和呼叫方式非常混亂,而且基於事件的非同步模型寫起來不友好,相容性不好.

基本特性
/*
		更加簡單的資料獲取方式,功能更強大,更靈活,可以看做是xhr升級版
		基於Promise實現
*/
基本用法

Example

fetch('/abc').then(data=>{
	return data.text();
}).then(ret=>{
	// 注意這裡得到的才是最終的資料
	console.log(ret);
})

Example1

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>

<body>
<div id="app">

</div>

<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
    var vm = new Vue({
        el: '#app',
        data: {},
        methods: {}
    })
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<script type="text/javascript">
    /*
        Fetch API基本用法
     */
    fetch('http://localhost:3000/fdata').then(function (data) {
        // text() 方法屬於fetchAPI的一部分,他返回一個Promise例項物件,用於獲取後臺返回資料
        return data.text();
    }).then(function (data) {
        // 這裡得到的才是最終的資料
        console.log(data);
    })
</script>

</body>
</html>

Example2

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
		<title>Examples</title>
		<meta name="description" content="">
		<meta name="keywords" content="">
		<link href="" rel="stylesheet">

		<script type="text/javascript" src="lib/vue.js"></script>
	</head>
	<body>

		<div id="box">
			<button @click="handleClick()">獲取影片資訊</button>
			<ul>
				<li v-for="data in datalist">
					<h3>{{ data.name }}</h3>
					<img :src="data.poster">
				</li>
			</ul>
		</div>

		<script>
			new Vue({
				el: "#box",
				data: {
					datalist: []
				},
				methods: {
					handleClick() {
						fetch("./json/test.json").then(res => res.json()).then(res => {
							console.log(res.data.films)
							this.datalist = res.data.films
						})
					}
				}
			})
		</script>


		<!-- new Vue({
		el: "#box",
		data:{
			datalist:["111","222","333"]
		}
	}) -->
	</body>
</html>
fetch請求引數

常用配置選項

/*
		method(String): HTTP請求方法,預設為GET(GET,POST,PUT,DELETE)
		body(String): HTTP的請求引數
		headers(Object) HTTP的請求頭,預設為{}
*/

GET請求方式的引數傳遞

fetch('/abc?id=123').then(data=>{
	return data.text();
}).then(ret=>{
	// 注意這裡得到的才是最終的資料
	console.log(ret)
})


fetch('/abc/123',{
	method 'get'
}).then(data=>{
	return data.text();
}).then(ret=>{
	// 注意這裡得到的才是最終的資料
	console.log(ret);
});

Example1

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>

<body>
<div id="app">

</div>

<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
    var vm = new Vue({
        el: '#app',
        data: {},
        methods: {}
    })
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<script type="text/javascript">
    /*
        Fetch API:  呼叫介面傳遞引數
     */
    // fetch('http://localhost:3000/books?id=123',{
    //     method: 'get'
    // })
    // .then(function (data) {
    //     return data.text();
    // }).then(function (data) {
    //     console.log(data)
    // });

    fetch('http://localhost:3000/books/123',{
        method: 'get'
    })
        .then(function (data) {
            return data.text();
        }).then(function (data) {
        console.log(data)
    });
</script>

</body>
</html>

POST請求方式引數傳遞

fetch('/books',{
	method: 'post',
	body: 'uname=list&pwd=123',
	headers: {
		'Content-Type': 'application/x-www-form-urlencoded',
}
}).then(data=>{
		return data.text();
}).then(ret=>{
		console.log(ret);
})
fetch響應結果

響應資料格式

/*
		text():  將返回體處理成字串型別
		json():  返回結果和JSON.parse(responseText)一樣
*/

fetch('/abc' then(data=>{
  // return data.text();
  return data.json();
}),then(ret=>{
  console.log(ret);
});

axios請求元件

axios基本特性
/*
		axios是一個基於Promise用於瀏覽器和node.js的HTTP客戶端.
			具有以下特徵:
					支援瀏覽器和node.js
					支援promise
					能攔截請求和響應
					自動轉換JSON資料
*/
axios基本用法
axios.get('/adata')
	.then(ret=>{
		// data屬性名稱是固定的,用於獲取後臺響應的資料
		console.log(ret.data)
})

Example1

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script type="text/javascript">
    axios.get('http://localhost:3000/adata').then(function (ret) {
        // 注意data屬性是固定的用法,用於獲取後臺的實際資料
        console.log(ret.data)
    })
</script>
</body>
</html>
axios的常用api

GET傳遞引數

/*
		通過URL傳遞引數
		通過params選項傳遞引數
*/

Exmaple2

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script type="text/javascript">
    // axios.get('http://localhost:3000/axios?id=1234').then(function (ret) {
    //     // 注意data屬性是固定的用法,用於獲取後臺的實際資料
    //     console.log(ret.data)
    // })

    axios.get('http://localhost:3000/adata', {
        params: {
            id: 700
        }
    })
        .then(function (ret) {
            console.log(ret.data)
        })

    // axios.get('http://localhost:3000/axios/1234').then(function (ret) {
    //     // 注意data屬性是固定的用法,用於獲取後臺的實際資料
    //     console.log(ret.data)
    // })
</script>
</body>
</html>

POST傳遞引數

通過選項傳遞引數(預設傳遞的是json格式的資料)

Example1

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script type="text/javascript">
    axios.post('http://localhost:3000/axios', {
      uname: 'lisi',
      pwd: 123
    }).then(function(ret){
      console.log(ret.data)
    })
</script>
</body>
</html>

通過URLSearchParams傳遞引數(application/x-www-form-urlencoded)

Example2

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script type="text/javascript">
    var params = new URLSearchParams();
    params.append('uname','youmen');
    params.append('pwd','123');
    axios.post('http://localhost:3000/axios',params).then(function(ret) {
        console.log(ret.data)
    })
</script>
</body>
</html>
axios的響應結果
/*
		data: 實際響應回來的資料
		header: 響應頭資訊
		status: 響應狀態碼
		statusText: 響應狀態資訊
*/

Example1

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script type="text/javascript">
    /*
        axios 響應式結果與全域性配置
     */
    axios.get('http://localhost:3000/axios-json').then(function(ret) {
        console.log(ret.data)
    })
</script>
</body>
</html>
axios的全域性配置
/*
		axios.default.timeout=3000; //超時時間
				axios.defaults.baseURL='http://localhost:3000/app';  // 預設地址
				
		axios.defaults.headers['mytoken'] = 'asadfjksdfjkdsaf'  // 設定請求頭
*/

Example1

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script type="text/javascript">
    /*
        axios 響應式結果與全域性配置
     */
    axios.defaults.baseURI = 'http://localhost:3000/';
    // 設定頭資訊
    axios.defaults.headers['mytoken'] = 'hello';
    
    axios.get('axios-json').then(function(ret) {
        console.log(ret)
    })


</script>
</body>
</html>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
		<title>Examples</title>
		<meta name="description" content="">
		<meta name="keywords" content="">
		<link href="" rel="stylesheet">
		<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
		<script type="text/javascript" src="lib/vue.js"></script>
	</head>
	<body>

		<div id="box">
			<button @click="handleClick()">正在熱映</button>

			<ul>
				<li v-for="data in datalist">
					<h1>{{ data.name }}</h1>
					<img :src="data.poster">
				</li>
			</ul>
		</div>

		<script>
			new Vue({
				el: "#box",
				data: {
					datalist: []
				},
				methods: {
					handleClick() {
						axios.get("./json/test.json").then(res => {
							// axios 自歐東包裝data屬性 res.data
							console.log(res.data.data.films)
							this.datalist = res.data.data.films
						}).catch(err => {
							console.log(err);
						})
					}
				}
			})
		</script>
	</body>
</html>

相關文章