1、接口调用方式
- 原生 ajax
- 基于 jQuery 的 ajax
- fetch
- axios
2、异步
- JavaScript的执行环境是 单线程。
- 所谓单线程,是指 JS 引擎中负责解释和执行 JavaScript 代码的线程只有一个,也就是一次只能完成一项任务,这个任务执行完后才能执行下一个,它会阻塞其他任务。这个任务可称为主线程。
- 异步模式可以一起执行多个任务。
- JS中常见的异步调用:
- 定时器
- ajax
- 事件函数
3、promise
3.1 Promise 的基本使用
- 主要解决异步深层嵌套的问题。
- promise 提供了简洁的 API 使得异步操作更加容易。
console.log(Promise);
Promise 对象console.log(typeof Promise);
函数
Promise基本使用:
- 我们使用 new 来构建一个 Promise,Promise 的构造函数接收一个参数,是函数,并且传入两个参数:
resolve
(表示异步操作执行成功后的回调函数),reject
( 表示异步操作执行失败后的回调函数)。 - Promise 实例生成以后,可以用 then 方法指定 resolved 状态和 reject 状态的回调函数。
- 在 then 方法中,你也可以直接 return 数据而不是 Promise 对象,在后面的 then中就可以接收到数据了。
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Promise 的基本使用</title>
</head>
<body>
<script>
// Promise 主要解决异步深层嵌套的问题
// promise 提供了简洁的API 使得异步操作更加容易
console.log(Promise); // Promise对象
console.log(typeof Promise); // 函数
/*
1. Promise基本使用
我们使用new来构建一个Promise
Promise的构造函数接收一个参数,是函数,并且传入两个参数:
resolve: 表示异步操作执行成功后的回调函数
reject: 表示异步操作执行失败后的回调函数
*/
var p = new Promise(function (resolve, reject) {
// 2. 这里用于实现异步任务 setTimeout
setTimeout(function () {
var flag = true;
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>
</body>
</html>
3.2 基于 Promise 发送 Ajax 请求并解决回调地狱问题
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>基于Promise发送Ajax请求</title>
</head>
<body>
<script>
/*
then参数中的函数返回值
*/
function queryData(url) {
// 1.1 创建一个Promise实例
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) {
// 1.2 处理正常的情况
resolve(xhr.responseText);
} else {
// 1.3 处理异常情况
reject('服务器错误');
}
};
xhr.open('get', url);
xhr.send(null);
});
}
// 发送一个ajax请求
// queryData('http://localhost:3000/data')
// .then(function (data) {
// console.log(data);
// }, function (info) {
// console.log(info);
// });
// 发送多个ajax请求并且保证顺序
// 注意:这里需要开启一个服务器
queryData('http://localhost:3000/data1')
.then(function (data) {
console.log(data); // "Hello TOM!"
// 1.4 想要继续链式编程下去 需要 return
return queryData('http://localhost:3000/data2');
})
.then(function (data) {
console.log(data); // "Hello LISA!"
return new Promise(function (resolve, reject) {
setTimeout(() => {
resolve(123);
}, 1000);
});
})
// 在then方法中,你也可以直接return数据而不是Promise对象,在后面的then中就可以接收到数据了
.then(function (data) {
return 'hello';
})
.then(function (data) {
console.log(data); // "hello"
})
</script>
</body>
</html>
3.3 Promise 基本 API
(1)实例方法
-
.then()
:得到异步任务正确的结果。 -
.catch()
:获取异常信息。 -
.finally()
: 成功与否都会执行(不是正式标准) 。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Promise常用API-实例方法</title>
</head>
<body>
<script>
/* Promise常用API-实例方法 */
console.dir(Promise);
function foo() {
return new Promise(function (resolve, reject) {
setTimeout(() => {
resolve('success');
// 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); // "success"
}, function (data) {
// 获取异常信息
console.log(data);
})
.finally(function () {
// 成功与否都会执行(不是正式标准)
console.log('finished'); // "finished"
});
</script>
</body>
</html>
(2)静态方法
.all()
Promise.all
方法接受一个数组作参数,数组中的对象(p1、p2、p3)均为 promise 实例(如果不是一个 promise,该项会被用Promise.resolve
转换为一个 promise)。它的状态由这三个 promise 实例决定。.race()
Promise.race
方法同样接受一个数组作参数。当p1, p2, p3中有一个实例的状态发生改变(变为fulfilled
或rejected
),p 的状态就跟着改变。并把第一个改变状态的 promise 的返回值,传给 p 的回调函数。
<script>
// 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/p1');
var p2 = queryData('http://localhost:3000/p2');
var p3 = queryData('http://localhost:3000/p3');
Promise.all([p1, p2, p3]).then(function (result) {
// all 中的参数[p1,p2,p3]和返回的结果一一对应 ["Hello Tom!", "Hello Jerry!", "Hello Lisa!"]
console.log(result); // ["Hello Tom!", "Hello Jerry!", "Hello Lisa!"]
});
Promise.race([p1, p2, p3]).then(function (result) {
// 由于p1执行较快,Promise的then()将获得结果'p1'。p2,p3仍在继续执行,但执行结果将被丢弃。
console.log(result); // "Hello Tom!"
});
</script>
4、Fetch API 的概述与基本使用
4.1 fetch
- Fetch API 是新的 ajax 解决方案,Fetch会返回 Promise 。
- fetch 不是 ajax 的进一步封装,而是原生js,没有使用XMLHttpRequest 对象。
4.2 fetch 的基本使用
- fetch 就是 ajax + Promise,使用的方式和 jquery 提供的 $.ajax() 差不多 。
- fetc h默认的是 get 请求。
- 用法:
fetch(url, options).then()
用法:
<script>
/*
Fetch API 基本用法:
fetch(url).then()
第一个参数url:请求的路径,Fetch会返回Promise
所以我们可以使用then 拿到请求成功的结果
*/
fetch('http://localhost:3000/fdata').then(function (data) {
// text()方法属于fetch API的一部分,它返回一个Promise实例对象,用于获取后台返回的数据
return data.text();
}).then(function (data) {
// 在这个then里面我们能拿到最终的数据
console.log(data); // "Hello Fetch!"
});
</script>
4.3 fetch API 中的 HTTP 请求
- fetch(url, options).then()
- HTTP协议,它给我们提供了很多的方法,如 POST,GET,DELETE,UPDATE,PATCH 和 PUT。
- 默认的是 GET 请求。
- 需要在 options 对象中指定对应的 method。
- method:请求使用的方法 。
- post 和普通请求的时候需要在 options 中设置请求头 headers 和 body。
实例:
<script>
/*
Fetch API调用接口传递参数
*/
// 1. GET参数传递-传统URL 通过url ?的形式传参
fetch('http://localhost:3000/books?id=12', {
// get 请求可以省略不写 默认的是GET
method: 'get'
}).then(function (data) {
// 它返回一个Promise实例对象,用于获取后台返回的数据
return data.text();
}).then(function (data) {
// 在这个then里面我们能拿到最终的数据
console.log(data);
});
// 2. GET参数传递-restful形式的URL
fetch('http://localhost:3000/books/13', {
method: 'get'
}).then(function (data) {
return data.text();
}).then(function (data) {
console.log(data);
});
// // 3. DELETE请求方式参数传递
fetch('http://localhost:3000/books/14', {
method: 'delete'
}).then(function (data) {
return data.text();
}).then(function (data) {
console.log(data);
});
// 4.1 POST请求方式参数传递
fetch('http://localhost:3000/books', {
method: 'post',
// 传递数据
body: 'uname=lili&pwd=123456',
// 设置请求头
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).then(function (data) {
return data.text();
}).then(function (data) {
console.log(data);
});
// 4.2 POST请求方式参数传递
fetch('http://localhost:3000/books', {
method: 'post',
body: JSON.stringify({
uname: '筱雪',
pwd: '123456'
}),
headers: {
'Content-Type': 'application/json'
}
}).then(function (data) {
return data.text();
}).then(function (data) {
console.log(data);
});
// 5.PUT请求方式参数传递
fetch('http://localhost:3000/books/15', {
method: 'put',
body: JSON.stringify({
uname: '小明',
pwd: '123456'
}),
headers: {
'Content-Type': 'application/json'
}
}).then(function (data) {
return data.text();
}).then(function (data) {
console.log(data);
});
</script>
服务器端部分路由:
app.get('/books', (req, res) => {
res.send('传统的URL传递参数 id为:' + req.query.id);
});
app.get('/books/:id', (req, res) => {
res.send('Restful形式的URL传递参数 id为:' + req.params.id);
});
app.delete('/books/:id', (req, res) => {
res.send('DELETE请求传递参数 id为:' + req.params.id);
});
app.post('/books', (req, res) => {
res.send('POST请求传递参数 用户名为:' + req.body.uname + ' 密码为:' + req.body.pwd);
});
app.put('/books/:id', (req, res) => {
res.send('PUT请求传递参数 修改id为:' + req.params.id + ' 用户名为:' + req.body.uname + ' 密码为' + + req.body.pwd);
});
4.4 fetch API 中的响应格式
- 用 fetch 来获取数据,如果响应正常返回,我们首先看到的是一个 response 对象,其中包括返回的一堆原始字节,这些字节在收到后,需要我们通过调用方法将其转换为相应格式的数据,比如
JSON
,BLOB
或者TEXT
等等。
实例:
<script>
/*
Fetch响应结果的数据格式
*/
fetch('http://localhost:3000/json').then(function (data) {
// 将获取到的数据使用 json 转换对象
// return data.json();
// 将获取到的数据 转换成字符串
return data.text();
}).then(function (data) {
// console.log(typeof data); // "object"
// console.log(data); // {uname: "小西", age: 13, gender: "female"}
var obj = JSON.parse(data); // 把字符串转化为JSON对象
console.log(obj.uname, obj.age, obj.gender); // 小西 13 female
});
</script>
服务器端路由:
app.get('/json', (req, res) => {
res.json({
uname: '小西',
age: 13,
gender: 'female'
});
});
5、axios
- 基于 promise 用于浏览器和 node.js 的 http 客户端。
- 支持浏览器和 node.js 。
- 支持 promise
- 能拦截请求和响应。
- 自动转换 JSON 数据
- 能转换请求和响应数据。
5.1 axios 基础用法
- get 和 delete请求传递参数
- 通过传统的 url 以 ? 的形式传递参数
- restful 形式传递参数
- 通过 params 形式传递参数
- post 和 put 请求传递参数
- 通过选项传递参数
- 通过 URLSearchParams 传递参数
实例:
<script src="js/axios.js"></script>
<script>
/*
axios请求参数传递
*/
// 1. 发送get 请求
axios.get('http://localhost:3000/adata').then(function (ret) {
// 拿到 ret 是一个对象, 所有的对象都存在ret的 data 属性里面
// 注意data属性是固定的用法,用于获取后台的实际数据
console.log(ret.data); // "Hello axios!"
console.log(ret); // Object
});
// 2. get 请求传递参数
// 2.1 通过传统的url以 ? 的形式传递参数
axios.get('http://localhost:3000/axios?id=10').then(function (ret) {
console.log(ret.data); // "axios get传递参数 id:10"
});
// 2.2 restful 形式传递参数
axios.get('http://localhost:3000/axios/11').then(function (ret) {
console.log(ret.data); // "axios get(Restful)传递参数 id:11"
});
// 2.3 通过params形式传递参数
axios.get('http://localhost:3000/axios', {
params: {
id: 12
}
}).then(function (ret) {
console.log(ret.data); // "axios get传递参数 id:12"
});
// 3. axios delete请求传参 传参的形式和 get请求一样
axios.delete('http://localhost:3000/axios', {
params: {
id: 13
}
}).then(function (ret) {
console.log(ret.data); // "axios delete传递参数 id:13"
});
// 4. axios的post请求
// 4.1 通过选项传递参数
axios.post('http://localhost:3000/axios', {
uname: '小西',
pwd: 123456
}).then(function (ret) {
console.log(ret.data);
});
// 4.2 通过 URLSearchParams 传递参数
var params = new URLSearchParams();
params.append('uname', '小五');
params.append('pwd', '12345');
axios.post('http://localhost:3000/axios', params).then(function (ret) {
console.log(ret.data); // "axios post传递参数 用户名:小五 密码:12345"
});
// 5. axios put请求传参和post请求一样
axios.put('http://localhost:3000/axios/123', {
uname: '小蓝',
pwd: 123456789
}).then(function (ret) {
console.log(ret.data)
});
</script>
服务器端部分代码:
app.get('/adata', (req, res) => {
res.send('Hello axios!');
});
app.get('/axios', (req, res) => {
res.send('axios get传递参数 id:' + req.query.id);
});
app.get('/axios/:id', (req, res) => {
res.send('axios get(Restful)传递参数 id:' + req.params.id);
});
app.delete('/axios', (req, res) => {
res.send('axios delete传递参数 id:' + req.query.id)
});
app.post('/axios', (req, res) => {
res.send('axios post传递参数 用户名:' + req.body.uname + ' 密码:' + req.body.pwd)
});
app.put('/axios/:id', (req, res) => {
res.send('axiosput传递参数 id:' + req.params.id + ' 用户名:' + req.body.uname + ' 密码:' + req.body.pwd)
});
5.2 axios 全局配置
// 配置请求的基准URL地址(配置公共的请求头)
axios.defaults.baseURL = 'http://localhost:3000/';
// 配置请求头信息
axios.defaults.headers['mytoken'] = 'hello';
// 配置超时时间
axios.defaults.timeout = 2500;
// 配置公共的post的 Content-Type
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
5.3 axios 拦截器
- 请求拦截器
- 请求拦截器的作用是在请求发送前进行一些操作
- 例如在每个请求体里加上token,统一做了处理,如果以后要改也非常容易。
- 请求拦截器的作用是在请求发送前进行一些操作
- 响应拦截器
- 响应拦截器的作用是在接收到响应后进行一些操作
- 例如在服务器返回登录状态失效,需要重新登录的时候,跳转到登录页。
- 响应拦截器的作用是在接收到响应后进行一些操作
实例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>axios拦截器</title>
</head>
<body>
<script src="js/axios.js"></script>
<script>
/*
axios拦截器
*/
// 1. 请求拦截器
axios.interceptors.request.use(function (config) {
console.log(config.url); // http://localhost:3000/adata
// 1.1 任何请求都会经过这一步 在发送请求之前做些什么
config.headers.mytoken = '你好';
// 1.2 这里一定要return 否则配置不成功
return config;
}, function (err) {
// 1.3 对请求错误做点什么
console.log(err);
});
// 2. 响应拦截器
axios.interceptors.response.use(function (res) {
console.log(res);
// 2.1 在接收响应做些什么
var data = res.data;
return data;
}, function (err) {
// 2.2 对响应错误做点什么
console.log(err);
});
axios.get('http://localhost:3000/adata').then(function (data) {
console.log(data)
});
</script>
</body>
</html>
6、async 和 await
-
async 作为一个关键字放到函数前面
- 任何一个
async
函数都会隐式返回一个promise
- 任何一个
-
await
关键字只能在使用async
定义的函数中使用- await 后面可以直接跟一个 Promise 实例对象
- await 函数不能单独使用
-
async/await 让异步代码看起来、表现起来更像同步代码
-
async 和 await 好处:
- async 搭配 await 是 ES7 提出的,它的实现是基于Promise。
-
注意细节点:
- await 函数不能单独使用,而且 async 函数返回的是一个 Promise 对象,可以使用 then 函数添加回调函数。当函数执行的时候,一旦遇到 await 函数就会先返回一个 Promise 对象,等到异步操作完成,再去执行后面的语句。
实例:async 函数基本用法
- await 函数不能单独使用,而且 async 函数返回的是一个 Promise 对象,可以使用 then 函数添加回调函数。当函数执行的时候,一旦遇到 await 函数就会先返回一个 Promise 对象,等到异步操作完成,再去执行后面的语句。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script src="js/axios.js"></script>
<script>
/*
async/await 处理异步操作:
async函数返回一个Promise实例对象
await后面可以直接跟一个Promise实例对象
*/
// 1.async 基础用法
// 1.1 async作为一个关键字放到函数前面
async function queryData() {
// 1.2 await关键字只能在使用async定义的函数中使用 await后面可以直接跟一个Promise实例对象
var ret = await new Promise(function (resolve, reject) {
setTimeout(() => {
resolve('你好');
}, 1000);
});
// console.log(ret.data);
return ret;
}
// 1.3 任何一个async函数都会隐式返回一个promise 我们可以使用then进行链式编程
queryData().then(function (data) {
console.log(data);
});
</script>
</body>
</html>
实例:async函数处理多个异步请求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script src="js/axios.js"></script>
<script>
/*
async/await处理多个异步任务
*/
axios.defaults.baseURL = 'http://localhost:3000';
async function queryData() {
// 添加await之后 当前的await返回结果之后才会执行后面的代码
var info = await axios.get('async1');
// 让异步代码看起来、表现起来更像同步代码
var ret = await axios.get('async2?info=' + info.data);
return ret.data;
}
queryData().then(function (data) {
console.log(data)
});
</script>
</body>
</html>