0
点赞
收藏
分享

微信扫一扫

AJAX(笔记06) - 原生AJAX - 请求超时、网络异常、取消请求和重复请求处理

开发的产品上线后,难免会遇到请求超时或网络异常的情况,在客户端设置超时处理和异常提醒,可以提升用户体验。

手动取消请求和取消重复发送请求,可以节省服务端资源;

这篇,来实现这些需求;


搭建Web服务环境

之前讲过 Express 快速启动Web服务,需要复习的同学请看:

​​AJAX(笔记03) - 原生AJAX - Node.js 和 Express 的简介、安装​​

新建 server.js 服务端文件:

const express = require('express')
const app = express()
app.get('/delay', (request, response) => {
response.setHeader('Access-Control-Allow-Origin', '*')
setTimeout(() => {
response.send('Hello Ajax!')
}, 3000)
})
app.listen('8000', () => {
console.log('Web服务已经启动,端口8000监听中... ...');
})

提示:设置延迟3秒再发送数据的函数,模拟请求时长;

启用服务:

> nodemon server.js


创建前端AJAX

需求是点击按钮发送请求,获得服务器响应数据;

新建 ajax_delay.html ,写点结构样式

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#result{
width: 200px;
height: 100px;
border:1px solid #394;
}
</style>
</head>
<body>
<button>点击按钮发送请求</button>
<div id="result">

</div>
</body>
</html>

看下效果:

AJAX(笔记06) - 原生AJAX - 请求超时、网络异常、取消请求和重复请求处理_AJAX

在当前文档里,写下ajax的JS部分;

let btn = document.getElementsByTagName('button')[0]
let res = document.getElementById('result')
btn.onclick = function(){
let xhr = new XMLHttpRequest();
xhr.open("GET","http://127.0.0.1:8000/delay")
xhr.send()
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status>=200 && xhr.status <300){
res.innerHTML = xhr.response
}
}
}
}

提示:由于服务端延迟3秒显示数据;

观察 Network 中的响应:

AJAX(笔记06) - 原生AJAX - 请求超时、网络异常、取消请求和重复请求处理_重复请求_02

status 和 time 的状态是 pending ...  , 3秒过后显示结果:

AJAX(笔记06) - 原生AJAX - 请求超时、网络异常、取消请求和重复请求处理_重复请求_03

status 状态码200,time 用时 3秒;


请求超时设置

let btn = document.getElementsByTagName('button')[0]
let res = document.getElementById('result')
btn.onclick = function(){
let xhr = new XMLHttpRequest();
// 超时设置2秒
xhr.timeout = 2000
xhr.open("GET","http://127.0.0.1:8000/delay")
xhr.send()
// ... 代码省略
}

提示:只需设置超时时长,超时后自动取消请求;

点击按钮看效果:

AJAX(笔记06) - 原生AJAX - 请求超时、网络异常、取消请求和重复请求处理_网络异常_04

2秒后,自动取消请求;


请求超时回调

let btn = document.getElementsByTagName('button')[0]
let res = document.getElementById('result')
btn.onclick = function(){
let xhr = new XMLHttpRequest();
// 超时设置2秒
xhr.timeout = 2000
// 超时设置回调
xhr.ontimeout = function(){
console.log('请求超时了');
}
// .... 代码省略
}

提示:超时后会取消请求,并触发超时回调函数,在控制台输出提示信息;


网络异常回调

let btn = document.getElementsByTagName('button')[0]
let res = document.getElementById('result')
btn.onclick = function(){
let xhr = new XMLHttpRequest();
// 超时设置2秒
xhr.timeout = 2000
// 超时设置回调
xhr.ontimeout = function(){
console.log('请求超时了');
}
// 网络异常回调
xhr.onerror = function(){
console.log("请检查网络...");
}
// .... 代码省略
}

开发者工具可以模拟断线的情况:

AJAX(笔记06) - 原生AJAX - 请求超时、网络异常、取消请求和重复请求处理_请求超时_05

点击按钮,查看效果:

AJAX(笔记06) - 原生AJAX - 请求超时、网络异常、取消请求和重复请求处理_网络异常_06

结果显示失败(failed),控制台输出提示信息;


手动取消请求

这次增加个按钮用来取消请求,

    <button>点击按钮发送请求</button>
<div id="result">

</div>
<button>点击按钮取消请求</button>

看下效果:

AJAX(笔记06) - 原生AJAX - 请求超时、网络异常、取消请求和重复请求处理_网络异常_07

修改下前端代码:后端代码不用动;

// 获取元素对象
let btns = document.getElementsByTagName('button')
let res = document.getElementById('result')
let xhr = null
// 发起请求按钮
btns[0].onclick = function () {
xhr = new XMLHttpRequest();
xhr.open("GET", "http://127.0.0.1:8000/delay")
xhr.send()
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
res.innerHTML = xhr.response
}
}
}
}
// 取消请求按钮
btns[1].onclick = function(){
xhr.abort()
}

提示:使用 xhr.abort() 方法来取消请求;

之所以把 xhr 定义在外面,是因为放在发起请求的按钮里面,那取消请求的按钮就调不到 xhr 对象了;

看下效果:

AJAX(笔记06) - 原生AJAX - 请求超时、网络异常、取消请求和重复请求处理_AJAX_08

提示:连续3次发起请求,又手动取消请求;

status 的状态变化,发起请求时是 pending ... ,取消请求时是 canceled ... ;


重复发送请求

实际应用中,用户可能频繁点击按钮来重复获取数据,给服务器带来很大压力,如图:

AJAX(笔记06) - 原生AJAX - 请求超时、网络异常、取消请求和重复请求处理_请求超时_09

服务端越是响应慢,用户点的越勤快,会造成很多重复请求;如果可以发现重复的请求时,把之前的请求 abort 掉,这样就不怕用户重复点击请求了;

可以设置一个开关,当请求的时候发现已有请求则中止请求;

let btn = document.getElementsByTagName('button')[0]
let res = document.getElementById('result')
let xhr = null
// 设置开关,代表是否正在发送请求
let isSending = false
btn.onclick = function () {
// 判断开关
if(isSending) xhr.abort()
xhr = new XMLHttpRequest();
// 发送请求前,打开开关
isSending = true
xhr.open("GET", "http://127.0.0.1:8000/delay")
xhr.send()
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
// 关闭开关
isSending = false
if (xhr.status >= 200 && xhr.status < 300) {
res.innerHTML = xhr.response
}
}
}
}

提示:设置开关的作用是每当点击按钮就都要先判断一下当前是不是处在请求中。如果是,就 abort 掉,并开启一个新的请求;如果不是,就开启一个新的请求,并打开开关,直到响应状态完成后再关闭开关。

看下效果:

AJAX(笔记06) - 原生AJAX - 请求超时、网络异常、取消请求和重复请求处理_重复请求_10

这样的好处就节省了重复请求的资源。

举报

相关推荐

0 条评论