零.Promise
1.什么是Promise?
Promise是JS中进行异步编程的一种新的解决方案,(旧方案是单纯使用回调函数)
语法上,Promise是一个对象,从Promise对象可以获取异步操作的消息
2.使用Promise有什么好处?
- Promise支持链式调用,可以避免回调地狱(回调地狱的终极解决方案:async/await)
- Promise对象提供了简介的API,使用控制异步操作变得容易
3.Promise的基本用法
var p = new Promise(function(resolve,reject){//实例化Promise对象
resolve(data);// 成功时调用 resolve()
reject(err); // 失败时调用 reject()
});
p.then(function(data){
console.log(data);// 从resolve得到正常结果,data为resolve中的参数
},function(err){
console.log(arr);// 从reject得到错误信息,err为reject中的参数
});
4.Promise的基本流程
5.pending,fulfilled和rejected是什么?
- Promise类的实例对象是有状态(state)的,对应三个值:pending(待定)、fullfilled(成功)、rejected(失败)
- 实例的初始状态为pending,一旦由pending状态落定成fulfilled状态或rejected状态,就不可再次改变,该过程是不可逆的
- 与之对应,Promise类实例对象有成功的结果(value)和失败的原因(reason),默认值都为undefined,只有状态被改变后(pending==>fullfilled或者pending==>rejected)才会为其赋值。
Promsie内部的state、value、reason是私有的,外界是访问不到的
6.resolve和reject是什么?
在Promise的实例化对象中,存在一个用于处理异步任务的构造函数
resolve和reject就是该构造函数的两个形参,用于处理成功和失败两种情况
- resolve作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
- reject作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
7.参数executor
什么是executor?
executor(读作:[ɪɡˈzekjətə®]),是带有 resolve 和 reject 两个参数的函数 。即(resolve,reject)=>{...}
Promise构造函数执行时立即调用executor函数,resolve和reject两个函数作为参数传递给executor(executor在Promise构造函数返回新建对象时被调用)
executor的resolve和reject被调用时改变Promise的状态
- resolve 和 reject 函数被调用时,分别将promise的状态改为fulfilled(完成)或rejected(失败)。
executor 内部通常会执行一些异步操作 - 一旦完成,可以调用resolve函数来将promise状态改成fulfilled,
或者在发生错误时将它的状态改为rejected。 - 如果在executor函数中抛出一个错误,那么该promise 状态为rejected。
executor函数的返回值被忽略。
8.then()和catch()是什么?
then方法
then()的作用是为 Promise 实例添加状态改变时的回调函数。
then方法可以有两个参数:
第一个是resolve状态的回调函数
第二个是reject状态的回调函数(可选)
then方法返回的是**一个新的Promise实例(**不是原来那个Promise实例)
回顾:Promise接收一个函数作为参数,这个函数有两个参数,第二个参数可选,分别是resolve和reject,
这两个参数分别和then方法的两个参数对应。
catch方法
catch方法就是then方法的语法糖,是.then(null, rejection)或.then(undefined, rejection)的别名
也就是说,catch也是then,它用于捕获错误,它的参数也就是then的第二个参数。
9.Promise.race()和Promise.all()是什么?
promise中的all方法和race方法
这两个方法,都是并行执行多个异步操作
区别:all方法遵循“谁跑得慢,以谁为准执行回调”,race方法遵循的是“谁跑的快,以谁为准执行回调”
示例
let p1 = Promise.resolve('aaa')
let p2 = Promise.resolve('bbb')
let p3 = Promise.reject('ccc')
let p4 = Promise.resolve('ddd')
Promise.all([p1, p2, p3, p4]).then(res => {
console.log(res); //返回数组
}).catch(err => {
console.log(err);
});
Promise.race([p1, p2, p3, p4]).then(res => {
console.log(res); //返回数组
}).catch(err => {
console.log(err);
});
结果:先输出aaa,再输出ccc
使用场景
Promise.all()的使用场景:一个操作同时需要不同接口返回的数据
Promise.race()的使用场景:若干服务器的若干接口都提供同样的服务,而不知道哪个接口更快==>哪个接口的数据先回来就用哪个接口的数据。
一.AJAX
1.什么是Ajax?
AJAX(Asynchronous Javascript And XML)即“异步Javascript和XML”,是⼀种创建交互式⽹⻚应
⽤的⽹⻚开发技术
使用Javascript语言与服务器进行异步交互,传输的数据为XML等格式。
可以在不重新加载整个网页的情况下,与服务器交换数据,并且更新部分网页
2.AJAX的特点
当服务器响应时,不用刷新整个浏览器页面,而是可以局部刷新
3.AJAX的原理
在用户与服务器之间加一个中间层(AJAX引擎),
用XMLHttpRequest对象想服务器发送异步请求,从服务器获取数据,
通过javascript来操作DOM,从而更新页面,使得用户操作和服务器响应异步化.
4.AJAX的优缺点
优点
- 异步交互,增强了交互体验
- 因为服务器无需响应整个页面,只需要响应部分内容,大大减轻服务器压力
缺点
- 增多了对服务器的访问次数,给服务器增加了压力
- AJAX是在浏览器中使用javascript完成的,因此还需要处理浏览器的兼容性问题
- 不能应用在所有场景,很多时候还需要使用同步交互
5.AJAX的实现步骤
- 创建XMLHttpRequest对象
- 通过open()方法与服务器建立连接
- 构建请求所需的数据内容,并通过send()方法发送给服务器端
- 通过onreadystatechange事件监听服务器端的通信状态
- 接收并处理服务器端向客户端响应的数据结果
- 将处理结果更新到HTML页面中
6.xhr.readyState:返回当前请求的状态
xhr.readyState = 0时-未初始化,对象已建立,尚未调用open()
xhr.readyState = 1时-初始化,对象建立未调用send()
xhr.readyState = 2时-发送数据,send()方法调用,但是当前的状态及http头未知,请求未完成
xhr.readyState = 3时-数据传输中,接受部分数据
xhr.readyState = 4时-响应内容解析完成
7.xhr.state:http常见状态码
1**~5**的大概意思
1**:请求收到,继续处理
2**:操作成功收到,分析、接受
3**:完成此请求必须进一步处理
4**:请求包含一个错误语法或不能完成
5**:服务器执行一个完全有效请求失败
常见状态码
200(成功)服务器已成功处理了请求。
301,永久性重定向,表示资源已被分配了新的 URL
302,临时性重定向,表示资源临时被分配了新的 URL
400(错误请求)服务器不理解请求的语法
401表示发送的请求需要有通过HTTP认证的认证信息
403(禁止)服务器拒绝请求
404(未找到)服务器找不到请求网页
500,(服务器内部错误)服务器遇到错误,无法完成请求
503,表示服务器处于停机维护或超负载,无法处理请求
7.AJAX示例:用户名是否已经存在
代码
user.html
<label for="">用户名:</label>
<input type="text"><span></span>
<br>
<input type="button" value="Send" id="btn">
<script>
var span = document.querySelector("span");
//1.创建XMLHttpRequest实例对象
var xhr = new XMLHttpRequest();
document.getElementById("btn").addEventListener("click", () => {
//2.通过open方法与服务器建立连接
xhr.open("GET", "./user.php?user=" + document.querySelectorAll("input")[0].value, true);
//3.通过send方法把数据发送给服务器
xhr.send();
//4.使用onreadystatechange事件监听服务器返回的状态
xhr.onreadystatechange = callback;
});
function callback() {
//5.接收和分析服务器返回的数据
if (xhr.readyState == 4 && xhr.status === 200) {
// console.log(xhr.response);
if (xhr.responseText == 1) {
span.style.color = 'red';
span.innerHTML = '*用户名已存在!';
}
if (xhr.responseText == 2) {
span.style.color = 'green';
span.innerHTML = '*注册成功!';
}
}
}
user.php
<?php
$user=$_GET['user'];
$arr=['张三','李四','王五'];
if(in_array($user,$arr)){
echo 1;
}else{
echo 2;
}
?>
报错:‘null’ has been blocked by CORS policy,遇到跨域问题
解决方法
把代码写在PHPStudy的www文件夹下
打开服务器
把地址栏中www前面的改成localhost
即:http://localhost/user.html
8.AJAX的封装和使用
封装 AJAX
//封装一个ajax请求
function ajax(options) {
//创建XMLHttpRequest对象
const xhr = new XMLHttpRequest()
//初始化参数的内容
options = options || {}
options.type = (options.type || 'GET').toUpperCase()
options.dataType = options.dataType || 'json'
const params = options.data
//发送请求
if (options.type === 'GET') {
xhr.open('GET', options.url + '?' + params, true)
xhr.send(null)
} else if (options.type === 'POST') {
xhr.open('POST', options.url, true)
xhr.send(params)
//接收请求
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
let status = xhr.status
if (status >= 200 && status < 300) {
options.success && options.success(xhr.responseText, xhr.responseXML)
} else {
options.fail && options.fail(status)
}
}
}
}
使用封装好的ajax()函数
ajax({
type: 'post',
dataType: 'json',
data: {},
url: 'https://xxxx',
success: function(text,xml){//请求成功后的回调函数
console.log(text)
},
fail: function(status){请求失败后的回调函数
console.log(status)
}
})
三.axios
四.async和await
2022-01-28 async和await的定义和用法
2021-07-28 使用async和await改进Promise异步操作的写法
五.Fetch
1.定义
Fetch是ES6新增的通信方法,不是ajax,但是他本身实现数据通信,就是基于promise管理的
基本特征:
更加简单的数据获取方式,功能更强大、更灵活,可以看做是xhr的升级版
基于Promise实现
语法结构:
fetch(url)
.then(fn2)
.then(fn3)
...
.catch(fn)
2.基本用法
fetch('/abc').then(data => {
return data.text() // 返回一个Promise实例对象
}).then(res=>{
console.log(res)// 注意这里得到的才是最终的数据
})
*text()方法属于fetchAPI的一部分,它返回一个Promise实例对象,用于获取后台返回的数据
3.请求参数
3.1. 常用配置选项
- method(String):HTTP请求方法,默认为GET(GET、POST、PUT、DELETE)
- body(String):HTTP的请求参数
- headers(Object):HTTP的请求头,默认为{}
fetch('/abc',{
method:'GET'
}).then(data => {
return data.text() // 返回一个Promise实例对象
}).then(ret=>{
// 注意这里得到的才是最终的数据
console.log(ret)
})
3.2.GET请求方式的参数传递(其它方式略)
方式一
// client发送,从server端返回
fetch('/abc?id=123',{
method:'GET'
}).then(data => {
return data.text() // 返回一个Promise实例对象
}).then(ret=>{
console.log(ret)
})
// client发送,从server端返回
fetch('/abc?id=123',{
method:'GET'
}).then(data => {
return data.text() // 返回一个Promise实例对象
}).then(ret=>{
console.log(ret)
})
方式二
// client发送,从server端返回
fetch('/abc/123',{
method:'GET'
}).then(data => {
return data.text() // 返回一个Promise实例对象
}).then(ret=>{
console.log(ret)
})
3.3.响应结果
响应数据格式
- text():将返回体处理成字符串类型
- json():返回结果和JSON.parse(responseText)一样
// client发送,从server端返回
fetch('/abc').then(data => {
// return data.text()
return data.json()
}).then(data=>{
console.log(data) // JSON对象
console.log(data.uname) // JSON对象.属性
})
// server接收,并发送给client
app.get('/abc',(req,res)=>{
res.json({
uname: 'lisi',
age: 13,
gender: 'male'
})
})
4.优缺点
fetcht只对网络请求报错,对400,500都当做成功的请求,需要封装去处理
fetch默认不会带cookie,需要添加配置项
fetch不支持abort,不支持超时控制,使用setTimeout及Promise.reject的实现的超时控制并不能阻止请求过程继续在后台运行,造成了量的浪费
fetch没有办法原生监测请求的进度,而XHR可以