接口调用形式
- 原生ajax
- 基于jQuery的ajax
- fetch
- axios
异步
- JavaScript的执行环境是「单线程」
- 所谓单线程,是指JS引擎中负责解释和执行JavaScript代码的线程只有一个,也就是一次只能实现一项工作,这个工作执行完后能力执行下一个,它会「阻塞」其余工作。这个工作可称为主线程
- 异步模式能够一起执行多个工作
JS中常见的异步调用
- 定时任何
- ajax
- 事件函数
promise
- 次要解决异步深层嵌套的问题
- promise 提供了简洁的API 使得异步操作更加容易
<script type="text/javascript"> /* 1. Promise根本应用 咱们应用new来构建一个Promise Promise的构造函数接管一个参数,是函数,并且传入两个参数: resolve,reject, 别离示意异步操作执行胜利后的回调函数和异步操作执行失败后的回调函数 */ var p = new Promise(function(resolve, reject){ //2. 这里用于实现异步工作 setTimeout setTimeout(function(){ var flag = false; if(flag) { //3. 失常状况 resolve('hello'); }else{ //4. 异常情况 reject('出错了'); } }, 100); }); // 5 Promise实例生成当前,能够用then办法指定resolved状态和reject状态的回调函数 // 在then办法中,你也能够间接return数据而不是Promise对象,在前面的then中就能够接管到数据了 p.then(function(data){ console.log(data) },function(info){ console.log(info) }); </script>
基于Promise发送Ajax申请
<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>
服务器端
pip install
Flask==1.1.1Flask-Cors==3.0.8
from flask import Flask, jsonify, requestfrom flask_cors import CORS# 创立应用程序对象app = Flask(__name__)# pip install Flask-CorsCORS(app)@app.route('/data')def hello(): ''' hello申请 ''' # 间接返回字符串 return 'Hello, data'@app.route('/data1')def hello1(): ''' hello申请 ''' # 间接返回字符串 return 'Hello, data1'@app.route('/data2')def hello2(): ''' hello申请 ''' # 间接返回字符串 return 'Hello, data2'if __name__ == '__main__': # 以debug模式启动程序 app.run(debug = True)
Promise 根本API
实例办法
.then()
- 失去异步工作正确的后果
.catch()
- 获取异样信息
.finally()
- 胜利与否都会执行(不是正式规范)
<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>
静态方法
.all()
Promise.all
办法承受一个数组作参数,数组中的对象(p1、p2、p3)均为promise实例(如果不是一个promise,该项会被用Promise.resolve
转换为一个promise)。它的状态由这三个promise实例决定
.race()
Promise.race
办法同样承受一个数组作参数。当p1, p2, p3中有一个实例的状态产生扭转(变为fulfilled
或rejected
),p的状态就跟着扭转。并把第一个扭转状态的promise的返回值,传给p的回调函数
<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){ // 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" }) </script>
fetch
- Fetch API是新的ajax解决方案 Fetch会返回Promise
- fetch不是ajax的进一步封装,而是原生js,没有应用XMLHttpRequest对象。
- fetch(url, options).then()
<script type="text/javascript"> /* Fetch API 根本用法 fetch(url).then() 第一个参数申请的门路 Fetch会返回Promise 所以咱们能够应用then 拿到申请胜利的后果 */ fetch('http://localhost:3000/fdata').then(function(data){ // text()办法属于fetchAPI的一部分,它返回一个Promise实例对象,用于获取后盾返回的数据 return data.text(); }).then(function(data){ // 在这个then外面咱们能拿到最终的数据 console.log(data); }) </script>
fetch API 中的 HTTP 申请
- fetch(url, options).then()
HTTP协定,它给咱们提供了很多的办法,如POST,GET,DELETE,UPDATE,PATCH和PUT
- 默认的是 GET 申请
- 须要在 options 对象中 指定对应的 method method:申请应用的办法
- post 和 一般 申请的时候 须要在options 中 设置 申请头 headers 和 body
<script type="text/javascript"> /* Fetch API 调用接口传递参数 */ fetch('http://localhost:5000/books?id=123', { method: 'get' }) .then(function(data) { return data.text(); }).then(function(data) { console.log(data) }); fetch('http://localhost:5000/books/456', { method: 'get' }) .then(function(data) { return data.text(); }).then(function(data) { console.log(data) }); // fetch('http://localhost:5000/books/789', { method: 'delete' }) .then(function(data) { return data.text(); }).then(function(data) { console.log(data) }); // fetch('http://localhost:5000/books', { method: 'post', body: 'uname=lisi&pwd=123', headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }) .then(function(data) { return data.text(); }).then(function(data) { console.log(data) }); // fetch('http://localhost:5000/books_json', { 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) }); // fetch('http://localhost:5000/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) }); </script>
后盾代码:
from flask import Flask, jsonify, requestfrom flask_cors import CORS# 创立应用程序对象app = Flask(__name__)# pip install Flask-CorsCORS(app)@app.route('/books',methods=["GET","POST"])def hello(): ''' hello申请 ''' # 间接返回字符串 if request.method == 'GET': return request.args['id'] elif request.method == 'POST': return request.form['uname']@app.route('/books/<string:id>')def hello1(id): ''' hello申请 ''' # 间接返回字符串 return id@app.route('/books/<string:id>',methods=["DELETE"])def hello2(id): ''' hello申请 ''' # 间接返回字符串 return id@app.route('/books_json',methods=["POST"])def books_json(): ''' hello申请 ''' # 间接返回字符串 if request.method == 'POST': return request.json@app.route('/books/<string:id>',methods=["PUT"])def books_put_json(id): ''' hello申请 ''' # 间接返回字符串 return request.jsonif __name__ == '__main__': # 以debug模式启动程序 app.run(debug = True)
fetchAPI 中 响应格局
- 用fetch来获取数据,如果响应失常返回,咱们首先看到的是一个response对象,其中包含返回的一堆原始字节,这些字节须要在收到后,须要咱们通过调用办法将其转换为相应格局的数据,比方
JSON
,BLOB
或者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数据
- 能转换申请和响应数据
axios根底用法
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) })
axios 全局配置
# 配置公共的申请头 axios.defaults.baseURL = 'https://api.example.com';# 配置 超时工夫axios.defaults.timeout = 2500;# 配置公共的申请头axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;# 配置公共的 post 的 Content-Typeaxios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
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) })
图书列表案例
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Document</title> <link rel="stylesheet" type="text/css" href="css/index.css"></head><body> <div id="app"> <div class="grid"> <div> <h1>图书治理</h1> <div class="book"> <div> <label for="id"> 编号: </label> <input type="text" id="id" v-model='id' disabled="false" v-focus> <label for="name"> 名称: </label> <input type="text" id="name" v-model='name'> <button @click='handle' :disabled="submitFlag">提交</button> </div> </div> </div> <div class="total"> <span>图书总数:</span> <span>{{total}}</span> </div> <table> <thead> <tr> <th>编号</th> <th>名称</th> <th>工夫</th> <th>操作</th> </tr> </thead> <tbody> <tr :key='item.id' v-for='item in books'> <td>{{item.id}}</td> <td>{{item.name}}</td> <td>{{item.date | format}}</td> <td> <a href="" @click.prevent='toEdit(item.id)'>批改</a> <span>|</span> <a href="" @click.prevent='deleteBook(item.id)'>删除</a> </td> </tr> </tbody> </table> </div> </div> <script type="text/javascript" src="js/vue.js"></script> <script type="text/javascript" src="js/axios.js"></script> <script type="text/javascript"> /* 图书治理-增加图书 */ axios.defaults.baseURL = 'http://localhost:5000/'; axios.interceptors.response.use(function(res){ return res.data; }, function(error){ console.log(error) }); Vue.directive('focus', { inserted: function (el) { el.focus(); } }); Vue.filter('format',(dataStr) => { var time = new Date(dataStr); function timeAdd0(str) { if(str<10){ str='0'+str; } return str } var y = time.getFullYear(); var m = time.getMonth()+1; var d = time.getDate(); var h = time.getHours(); var mm = time.getMinutes(); var s = time.getSeconds(); return y+'-'+timeAdd0(m)+'-'+timeAdd0(d)+' '+timeAdd0(h)+':'+timeAdd0(mm)+':'+timeAdd0(s); }) var vm = new Vue({ el: '#app', data: { flag: false, submitFlag: false, id: '', name: '', books: [] }, methods: { handle: async function(){ if(this.flag) { // 编辑图书 var ret = await axios.put('books/' + this.id, { name: this.name }); if(ret.status == 200){ // 从新加载列表数据 this.queryData(); } this.flag = false; }else{ // 增加图书 var ret = await axios.post('books', { name: this.name }) if(ret.status == 200) { // 从新加载列表数据 this.queryData(); } } // 清空表单 this.id = ''; this.name = ''; }, toEdit: async function(id){ // flag状态位用于辨别编辑和增加操作 this.flag = true; // 依据id查问出对应的图书信息 var ret = await axios.get('books/' + id); this.id = ret.id; this.name = ret.name; }, deleteBook: async function(id){ // 删除图书 var ret = await axios.delete('books/' + id); console.log(ret) if(ret.status == 200) { // 从新加载列表数据 this.queryData(); } }, queryData: async function(){ // 调用后盾接口获取图书列表数据 // var ret = await axios.get('books'); // this.books = ret.data; this.books = await axios.get('books'); } }, computed: { total: function(){ // 计算图书的总数 return this.books.length; } }, watch: { name: async function(val) { // 验证图书名称是否曾经存在 var ret = await axios.get('/books/book/' + this.name); // console.log(ret) if(ret.status == 1) { // 图书名称存在 this.submitFlag = true; }else{ // 图书名称不存在 this.submitFlag = false; } } }, mounted: function(){ this.queryData(); } }); </script></body></html>
.grid { margin: auto; width: 530px; text-align: center;}.grid table { border-top: 1px solid #C2D89A; width: 100%; border-collapse: collapse;}.grid th,td { padding: 10; border: 1px dashed #F3DCAB; height: 35px; line-height: 35px;}.grid th { background-color: #F3DCAB;}.grid .book { padding-bottom: 10px; padding-top: 5px; background-color: #F3DCAB;}.grid .total { height: 30px; line-height: 30px; background-color: #F3DCAB; border-top: 1px solid #C2D89A;}
后盾代码:
# coding:utf-8import timefrom flask import Flask, jsonify, requestfrom flask_cors import CORSbookdata = [ { "id": 1, "name": "红楼梦", "date": 2525609975000 }, { "name": "三国演义", "date": 2525609975000, "id": 2 }, { "name": "水浒传", "date": 2525609975000, "id": 3 }, { "name": "西游记", "date": 2525609975000, "id": 4 }]last_id = len(bookdata) + 1# 创立应用程序对象app = Flask(__name__)# pip install Flask-CorsCORS(app)@app.route('/')def hello(): ''' hello申请 ''' # 间接返回字符串 return 'Hello, Flask World!'@app.route('/books', methods=["GET","POST"])def books(): global last_id if request.method == 'GET': # 间接返回字符串 return jsonify(bookdata) elif request.method == 'POST': body = request.json print(body['name']) book = {} book['id'] = last_id book['name'] = body['name'] book['date'] = int(time.time()*1000) bookdata.append(book) last_id+=1 return jsonify({'status': 200})@app.route('/books/book/<string:name>', methods=["GET"])def check_bookname(name): print('check_bookname' + name) if name in [book['name'] for book in bookdata]: return jsonify({'status': 1}) else: return jsonify({'status': 0})@app.route('/books/book/', methods=["GET"])def check_empty_bookname(): print('check_empty_bookname') return jsonify({'status': 0})@app.route('/books/<string:id>', methods=["GET","PUT","DELETE"])def manage_bookinfo(id): global bookdata if request.method == 'GET': books = list(filter(lambda x: x['id'] == int(id), bookdata)) return jsonify(books[0]) elif request.method == 'PUT': body = request.json books = list(filter(lambda x: x['id'] == int(id), bookdata)) book = books[0] book['name'] = body['name'] return jsonify({'status': 200}) elif request.method == 'DELETE': body = request.json books = list(filter(lambda x: x['id'] != int(id), bookdata)) bookdata = books return jsonify({'status': 200})if __name__ == '__main__': # 以debug模式启动程序 app.run(debug = True)