前后端交互
接口的调用方式
- 原生的js — 手写原生的ajax的实现过程
- 基于Jquery的ajax
- fetch(ajax的升级版)
- axios
// 安装服务
npm install http-server
// 设置启动端口
http-server -p 8000
URL地址格式
schema:// host:port/path?query#fragment
schema:协议 比如:http/https/ftp
host:域名或者ip地址
port:端口 http默认的端口是80 可以省略
path:路径 比如:/abc/a/b/c
query:查询的参数 比如:name=zhangsan&age=20
fragment:锚点(哈希地址hash) 用于定位页面的某个位置
// HTTP 请求方式
GET 查询
POST 添加
PUT 修改
DELETE 删除
Promise的用法
传统ajax的调用数据接口
- 异步调用
- 异步效果
- 定时任务
- ajax
- 事件函数
- 异步效果
- 多次异步调用的依赖
- 多次异步调用的结果顺序是不确定的
- 异步调用结果如果存在依赖需要,那就需要嵌套
// 逻辑代码
let ret = '----'
$.ajax({
url: 'http://localhost:3000/data',
success: function (data) {
ret = data;
console.log(ret);
}
})
console.log(ret); // hello word
// 服务代码
app.get('/data', (req,res) => {
res.send('hello word')
})
依赖分析
如果是同时调用不同的接口,打印的结果顺序是不确定
// 前端
$.ajax({
url: 'http://localhost:3000/data',
success: function (data) {
console.log(data);
}
})
$.ajax({
url: 'http://localhost:3000/data1',
success: function (data1) {
console.log(data1);
}
})
$.ajax({
url: 'http://localhost:3000/data2',
success: function (data2) {
console.log(data2);
}
})
// 服务器
app.get('/data', (req, res) => {
res.send('hello word')
})
app.get('/data1', (req, res) => {
res.send('hello xiaomao')
})
app.get('/data2', (req, res) => {
res.send('hello xiaoyang')
})
如何规定结果的顺序 – 必须使用回调函数
$.ajax({
url: 'http://localhost:3000/data',
success: function (data) {
console.log(data);
$.ajax({
url: 'http://localhost:3000/data1',
success: function (data1) {
console.log(data1);
$.ajax({
url: 'http://localhost:3000/data2',
success: function (data2) {
console.log(data2);
}
})
}
})
}
})
回调地狱
因为ajax的依赖关系导致一个非常深的函数的嵌套问题
function req1 () {
$.ajax({
url: 'http://localhost:3000/data',
success: function (data) {
console.log(data);
}
})
}
function req2 () {
$.ajax({
url: 'http://localhost:3000/data1',
success: function (data1) {
console.log(data1);
}
})
}
function req3 () {
$.ajax({
url: 'http://localhost:3000/data2',
success: function (data2) {
console.log(data);
}
})
}
Promise
Promise是用来实现异步处理的
优势:
- 可以避免多层的嵌套
- Promise提供了简洁API 让异步操作更简单
promise的使用
const promise = new Promise((resolve, reject) => {
if (失败) {
reject()
}
成功
resolve()
return promise
})
const p = new Promise(function (resolve, reject) {
// 这个位置是实现具体的异步任务的
setTimeout(function () {
var flag = false
if (flag) {
// 正常情况
resolve('hello')
} else {
reject('出错了')
}
}, 100)
})
调用.then
p.then(function(data){ }, function(error){ })
promise中使用ajax
function queryData (url) {
const 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);
})
链式调用
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);
})
返回普通值
queryData('http://localhost:3000/data').then(function (data) {
console.log(data);
return new Promise(function(resolve, reject){
setTimeout( () => {
resolve('123')
})
})
}).then(function (data) {
console.log(data);
return 'hellohhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh'
}).then(function (data) {
console.log(data);
})
peomise中其他的API – catch
语法:
queryData('http://localhost:3000/data').then(function (data) {
console.log(data);
}).catch(function(error) { console.log('发生错误', error) })
function queryData (url) {
var p = new Promise(function (resolve, reject) {
setTimeout(function () {
reject('服务器错误')
}, 100)
})
return p
}
queryData('http://locaohost:3000/data').then(function (data) {
console.log(data);
}).catch(function (error) {
console.log('发生错误:', error);
})
peomise中其他的API – finally
finally方法用于不管promise状态是如何的,都会执行
queryData('http://locaohost:3000/data').then(function (data) {
console.log(data);
}).catch(function (error) {
console.log('发生错误:', error);
}).finally(function(){
console.log('finally');
})
peomise中其他的API – all
Promise.all() 方法用于将多个promise实列,包装成一个新的promise对象
const p = Promise.all([p1,p2,p3])
Promise.all接收一个数组作为参数, p1,p2,p3都是Promise的实列,如果不是,就会优先调用下面的还没讲的方法resolve(),将参数转为 promise实列
Promise.all() 方法的参数可以不是数组,但是必须是 iterator 接口类型的,返回的每个成员都是的 promise实列
p 的状态由 p1 , p2 , p3 决定,分成两种情况
1、只有 p1,p2,p3状态都变成 fulfilled , p的状态才是 fulfilled 这个时候p1,p2,p3、返回只组成一个数组,传递给 p 的回调函数
2、 只要p1,p2,p3之中有一个被 rejected p的状态就变成 rejected ,这个时候第一个被 rejected 实列的返回值,会传递 p 的回调函数
var p1 = queryData('http://localhost:3000/data')
var p2 = queryData('http://localhost:3000/data1')
var p3 = queryData('http://localhost:3000/data2')
console.log(p1, p2, p3);
var p =Promise.all([p1, p2, p3]).then(function (result) {
console.log(result);
})
peomise中其他的API – race
race()同样是把多个 promise实列 包装成一个新的promise实列
const p = Promise.all([p1,p2,p3])
只要 p1,p2,p3 之中有一个实列先改变状态,p的状态就跟着改变,哪个先改变 promise实列的返回值,p接收的就是谁的返回值‘
fetch
是一种HTTP的请求方式,是XMLHttpRequest的一种替代方案,但是不是ajax的封装,是一种js属性,Fetch函数是原生的,没有使用XMLHttpRequest
fetch和ajax的差异
- fetch()使用promise,不使用回调函数,简化了写法,更简洁
- fetch使用的是模块化设计,API分散在多个对象上,输入、输出、状态都在同一个接口管理
- fetch是通过数据流(stream对象)处理数据的,可以分块读取,有利于提高网站的性能
使用方式
fetch(url).then(fn)
.then(fn1)
.catch(fn3)
fetch('http://localhost:3000/fdata')
.then(function(data){
// data.text() 返回的是一个Promise对象
// text()属性FecthApi的一部分,用于获取后台的数据
// console.log(data.text());
return data.text()
}).then(function(data){
console.log(data); // undefined
})
async function getJson () {
let url = 'http://localhost:3000/fdata';
try {
let response = await fetch(url)
console.log(response);
console.log(response.json());
} catch (error) {
console.log('Request Failed', error);
}
}
getJson ()
Response对象: 处理HTTP请求
async function fetchText () {
try{
let response = await fetch('http://localhost:3000/fdata');
console.log(response); // Response
}catch (error) {
console.log('Request Failed', error);
}
}
fetchText()
Response包含的数据通过Stream接口异步获取,但是他还包含一些同步的属性,对用HTTP回应的标头信息(Headers) 可以立即读取
async function fetchText () {
let response = await fetch('http://localhost:3000/fdata');
console.log(response.status); // 200
console.log(response.statusText); // OK
}
fetchText()
标头信息
Response.ok 返回一个布尔值
Response.status 属性返回的是一个数字 范围是 200 =< <=299
Response.statusText 属性返回的是一个字符串,表示HTTP回应的状态信息
Response.Type属性返回的请求类型 可能有下面的值
- basic: 普通请求 就是同源请求
- cors: 跨域请求
- error: 网络错误,主要使用 service Worker
- opaque: 如果fetch()请求的type属性设为 no-cors 就你会返回这个值,表示发出的是简单的跨域请求,类似表单的那种
- opaqueredirect: 如果fetch请求的redirect属性为manual 就会返回这个值
Response.redirected :属性返回一个布尔值,表示请求是否发生跳转
async function fetchText () {
let response = await fetch('http://localhost:3000/fdata');
if (response.status >= 200 && response.status < 300) {
return await response.text()
} else {
throw new Error(response.statusText)
}
}
console.log(fetchText());
axios
使用npm安装
npm install axios
使用 bower 安装
bower install axios
使用纱
yarn install axios
引入脚本
使用csdn
// 在线的网址
本地引入
<script src="./js/axios.js"></script>
语法:
axios.get('/data').then(ret => { cosole.log(ret.data) })
axios.get('http://localhost:3000/adata')
.then(function (ret) {
// data属性是固定的 用户获取后台响应的数据
// data是axios的API的一部分,用户获取后台数据
console.log(ret);
})
GET的使用方式
GET传递参数:
1、通过URL传递参数
2、通过params选项传递参数
通过URL传递参数
axios.get('/data?id=123').then(ret => { console.log(ret.data) })
第一种用法
// 数据请求
axios.get('http://localhost:3000/axios?id=123')
.then(ret => {
console.log(ret.data);
})
// 服务器数据
app.get('/axios', (req, res) => {
res.send('axios12345678' + req.query.id)
})
第二种用法
// 数据请求
axios.get('http://localhost:3000/axios/456')
.then(ret => {
console.log(ret.data);
})
// 服务器数据
app.get('/axios/:id', (req, res) => {
res.send('axios12345678' + req.params.id)
})
通过params选项传递参数
axios.get(url, {
params: {
id:123
}
}).then(function(ret){
console.log(ret)
})
// 数据请求
axios.get("http://localhost:3000/axios", {
params: {
id: 7890
}
}).then((ret) => {
console.log(ret.data)
})
// 服务器
app.get('/axios', (req, res) => {
res.send('axios12345678' + req.query.id)
})
delete的使用方式
通过url传递参数
axios.delete('/data?id=123').then(ret => {
console.log(ret)
})