关于浏览器请求队列和超时表现(canceled)

2024-08-23 01:18

本文主要是介绍关于浏览器请求队列和超时表现(canceled),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前端在向服务器 API 发送请求时一般会设置一个超时时间,避免超过期望时间的持续等待。

以 Axios 为例,一般会设置 timeout 请求超时选项。

但是浏览器判断超时并不是这么简单。

搭建环境

express + axios 搭建 web 服务。

在项目目录下安装依赖:npm i express axios

添加文件:

// start.js
const express = require('express')const PORT = 3000let app = express()app.use(express.static(path.join(__dirname, 'public')))
app.use('/api', require('./timeout'))app.listen(PORT, () => {console.log(`Sever listening on port ${PORT}`)
})
// timeout.js
const express = require('express');const router = express.Router()router.get('/timeout', async (req, res) => {// 用于查看服务器接收到请求的时机console.log('timeout')// 5 秒后响应setTimeout(() => {res.status(200).end('OK')}, 5000);
})module.exports = router
<!-- public/index.html -->
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><script src="https://unpkg.com/axios@0.24.0/dist/axios.min.js"></script></head><body><script>const instance = axios.create({timeout: 1000 // 超过1秒超时,中止请求})function fetch() {instance.get('/api/timeout')}fetch()</script></body>
</html>

运行 node start.js,访问 http://localhost:3000

正常超时

正常情况下,浏览器发送请求,超过设置的时间后,axios 就会主动中断请求。

F12 开发人员工具的网络面板中可以看到,请求状态为 canceled(已取消)。

在这里插入图片描述

竞态场景

实际场景下,页面中经常会有多个请求同时发起,而不同浏览器也会限制同一时间处理请求的最大数量。这就会产生竞态,首先发起的请求就会被优先处理。超过上限的请求会强制挂起(pending),当前面的请求接收响应移出队列,腾出位置,挂起的请求才允许发送给服务器。

关键在于,请求挂起的过程中消耗的时间仍参与超时时间计算。

这就会有一些无法预料的超时场景,例如:

  • A请求耗时长,B在等待A的时候消耗过多时间,等到处理B请求的时候,时间所剩无几,还没等服务器响应,浏览器就主动中断了B请求
  • A请求耗时长,B在等待A的时候达到超时时间,浏览器中止B请求,可怜B请求的服务器什么都还没做
  • 等等

相同地址竞态

同一时间,浏览器只会处理同一地址的一个请求,其它的会挂起。

// public/index.html
const instance = axios.create({timeout: 8000 // 超过8秒超时,中止请求
})function fetch() {instance.get('/api/timeout')
}// 同时发起两个相同地址的请求
fetch()
fetch()

同时发起两个相同地址的请求,仅处理第一个,后面的会挂起,等待前面的请求结束

在这里插入图片描述

5秒后(如果只考虑服务器处理的时间)第一个接收响应(处理完成),轮到第二个,此时第二个的请求时间已经消耗了5秒

在这里插入图片描述

达到8秒时间上限,浏览器中止第二个请求。

在这里插入图片描述

同源不同地址竞态

浏览器允许同域名下多个不同地址的并发请求,但也设置了数量上限,例如 Chrome 上限为 6 个。

添加多个不同地址的5秒响应接口:

const express = require('express');const router = express.Router()router.get('/timeout', async (req, res, next) => {console.log('timeout')// 5 秒后响应setTimeout(() => {res.status(200).end('OK')}, 5000);
})router.get('/timeout2', async (req, res, next) => {console.log('timeout2')setTimeout(() => {res.status(200).end('OK')}, 5000);
})router.get('/timeout3', async (req, res, next) => {console.log('timeout3')setTimeout(() => {res.status(200).end('OK')}, 5000);
})router.get('/timeout4', async (req, res, next) => {console.log('timeout4')setTimeout(() => {res.status(200).end('OK')}, 5000);
})router.get('/timeout5', async (req, res, next) => {console.log('timeout5')setTimeout(() => {res.status(200).end('OK')}, 5000);
})router.get('/timeout6', async (req, res, next) => {console.log('timeout6')setTimeout(() => {res.status(200).end('OK')}, 5000);
})router.get('/timeout7', async (req, res, next) => {console.log('timeout7')setTimeout(() => {res.status(200).end('OK')}, 5000);
})router.get('/timeout8', async (req, res, next) => {console.log('timeout8')setTimeout(() => {res.status(200).end('OK')}, 5000);
})module.exports = router
// public/index.html
const instance = axios.create({timeout: 8000 // 超过8秒超时,中止请求
})function fetch(num) {instance.get('/api/timeout' + (num || ''))
}// 同一时间发送多个不同地址的请求
['',2,3,4,5,6,7,8].forEach(v => fetch(v))

同一时间向同域名下不同地址的接口发送请求,最多处理6个请求,其它的全部挂起

在这里插入图片描述

5秒后(如果只考虑服务器处理的时间)优先处理的6个请求接收响应(处理完成),挂起的请求进行补位,此时剩余接口的请求时间已经消耗了5秒

在这里插入图片描述

达到8秒时间上限,浏览器中止超时的请求。

在这里插入图片描述

不同源下地址竞态

浏览器对不同源下的请求不进行竞态,这就是使用 CDN 提高资源并行加载效率的原因。这里就不做示例了。

关于同源参考:浏览器的同源策略

总结

  • 前端设置的请求超时时间是从 JS 发起请求开始计算
  • 浏览器同一时间处理请求有数量上限,超过上限的请求将被挂起,等待处理队列空闲才会依次处理剩下的请求
  • 浏览器挂起的请求依然参与超时时间计算
  • 为避免请求在真正发送到服务器之前被浏览器消耗时间,可以使用 CDN 等不同源的请求地址,或定制超时重试机制。

这篇关于关于浏览器请求队列和超时表现(canceled)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1097942

相关文章

hdu1180(广搜+优先队列)

此题要求最少到达目标点T的最短时间,所以我选择了广度优先搜索,并且要用到优先队列。 另外此题注意点较多,比如说可以在某个点停留,我wa了好多两次,就是因为忽略了这一点,然后参考了大神的思想,然后经过反复修改才AC的 这是我的代码 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<

poj 3190 优先队列+贪心

题意: 有n头牛,分别给他们挤奶的时间。 然后每头牛挤奶的时候都要在一个stall里面,并且每个stall每次只能占用一头牛。 问最少需要多少个stall,并输出每头牛所在的stall。 e.g 样例: INPUT: 51 102 43 65 84 7 OUTPUT: 412324 HINT: Explanation of the s

poj 2431 poj 3253 优先队列的运用

poj 2431: 题意: 一条路起点为0, 终点为l。 卡车初始时在0点,并且有p升油,假设油箱无限大。 给n个加油站,每个加油站距离终点 l 距离为 x[i],可以加的油量为fuel[i]。 问最少加几次油可以到达终点,若不能到达,输出-1。 解析: 《挑战程序设计竞赛》: “在卡车开往终点的途中,只有在加油站才可以加油。但是,如果认为“在到达加油站i时,就获得了一

poj3750约瑟夫环,循环队列

Description 有N个小孩围成一圈,给他们从1开始依次编号,现指定从第W个开始报数,报到第S个时,该小孩出列,然后从下一个小孩开始报数,仍是报到S个出列,如此重复下去,直到所有的小孩都出列(总人数不足S个时将循环报数),求小孩出列的顺序。 Input 第一行输入小孩的人数N(N<=64) 接下来每行输入一个小孩的名字(人名不超过15个字符) 最后一行输入W,S (W < N),用

POJ2010 贪心优先队列

c头牛,需要选n头(奇数);学校总共有f的资金, 每头牛分数score和学费cost,问合法招生方案中,中间分数(即排名第(n+1)/2)最高的是多少。 n头牛按照先score后cost从小到大排序; 枚举中间score的牛,  预处理左边与右边的最小花费和。 预处理直接优先队列贪心 public class Main {public static voi

zeroclipboard 粘贴板的应用示例, 兼容 Chrome、IE等多浏览器

zeroclipboard单个复制按钮和多个复制按钮的实现方法 最近网站改版想让复制代码功能在多个浏览器上都可以实现,最近看网上不少说我们的代码复制功能不好用的,我们最近将会增加代码高亮等功能,希望大家多多支持我们 zeroclipboard是一个跨浏览器的库类 它利用 Flash 进行复制,所以只要浏览器装有 Flash 就可以运行,而且比 IE 的

Java并发编程之——BlockingQueue(队列)

一、什么是BlockingQueue BlockingQueue即阻塞队列,从阻塞这个词可以看出,在某些情况下对阻塞队列的访问可能会造成阻塞。被阻塞的情况主要有如下两种: 1. 当队列满了的时候进行入队列操作2. 当队列空了的时候进行出队列操作123 因此,当一个线程试图对一个已经满了的队列进行入队列操作时,它将会被阻塞,除非有另一个线程做了出队列操作;同样,当一个线程试图对一个空

微软正式推出 Spartan 斯巴达浏览器

作为用于替代 IE 浏览器的下一代继任者,微软的 Project Spartan 斯巴达浏览器可算是吊足了玩家们的胃口!如今,在最新的 Windows 10 Build 10049 版本起,它终于正式登场了。 斯巴达浏览器搭载了全新的渲染引擎、新的用户界面并集成了 Cortana 语音助手。功能上新增了稍后阅读列表、阅读视图、F12开发者工具、支持网页注释 (手写涂鸦),可以保存到 O

PC与android平板通过浏览器监控Verybot的视频

下面这个视频是PC与android平板通过浏览器监控Verybot的视频:           http://v.youku.com/v_show/id_XNjYzNzYyMTIw.html

FreeRTOS学习笔记(六)队列

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、队列的基本内容1.1 队列的引入1.2 FreeRTOS 队列的功能与作用1.3 队列的结构体1.4 队列的使用流程 二、相关API详解2.1 xQueueCreate2.2 xQueueSend2.3 xQueueReceive2.4 xQueueSendFromISR2.5 xQueueRecei