深入探索前端开发中的浏览器事件模型与请求处理
我敬佩简单的快乐,那是复杂最后的避难所。 ---奥斯卡·王尔德-
在前端开发领域,浏览器事件模型和请求处理是构建交互性强、高性能网页应用的核心要素。作为前端开发者,深入理解这些概念并熟练运用相关技术,对于打造优质用户体验至关重要。在这篇文章中,我们将全面且深入地探讨浏览器事件模型、事件委托、浏览器请求(包括 Ajax、Fetch 和 Axios)等重要主题,为前端开发者提供详尽的知识储备和实践指导。
一、浏览器事件模型
(一)DOM事件概述
DOM(文档对象模型)是针对HTML和XML文档的API,它提供了一种结构化的方式来表示和操作页面内容。DOM事件则是用户或浏览器在文档上执行的操作,如点击、加载、鼠标移动等,开发者可以通过JavaScript代码来响应这些事件。
(二)DOM0级事件
- 基本使用方式
在DOM0级事件模型中,事件处理程序直接绑定在元素的属性上。例如,给一个按钮添加点击事件:
ini
var btn = document.getElementById('btn');
btn.onclick = function(){
console.log('this is a click event');
}
这里,onclick
是按钮元素的一个属性,将一个函数赋值给它,当按钮被点击时,该函数就会被执行。
- 事件处理程序中的
this
指向
在非严格模式下,如果指定的this
值为null
或undefined
,它会自动指向全局对象(在浏览器中为window
对象);若this
值为原始值(数字、字符串、布尔值),则会指向该原始值的自动包装对象。例如:
javascript
btn.onclick = function(){
console.log(this === window); // 在非严格模式下,输出为true
}
但在严格模式下,this
的值保持不变,不会自动指向全局对象。
- 事件对象
event
事件处理程序会自动传入event
对象,它包含了与事件相关的所有信息。在大多数浏览器中,可以通过函数参数获取事件对象,如:
javascript
btn.onclick = function(e){
console.log(e); // 事件对象
}
然而,在IE中,使用DOM0级方法添加事件处理程序时,event
是作为window
对象的一个属性存在的,需要通过window.event
来访问,如:
javascript
btn.onclick = function(){
console.log(window.event); // IE中访问事件对象
}
- 绑定多个事件处理程序
要为一个对象绑定多个函数,可以在事件处理程序中依次调用这些函数,例如:
javascript
function fn1(){
// do something
}
function fn2(){
// do something
}
btn.onclick = function(e){
fn1.call(this);
fn2.call(this);
}
这里通过call
方法来确保函数中的this
指向正确的对象(即按钮元素)。
(三)DOM2级事件
- 事件模型特点
DOM2级事件将属性升级为队列,通过addEventListener
和removeEventListener
方法来添加和移除事件处理程序。这使得一个元素可以绑定多个相同类型的事件处理程序,并且可以控制事件在捕获阶段或冒泡阶段执行。
addEventListener
方法
该方法接收三个参数:要处理的事件名、作为事件处理程序的函数、一个布尔值(true
代表在捕获阶段调用事件处理程序,false
表示在冒泡阶段调用,默认值为false
)。例如:
lua
btn.addEventListener('click',function(){
// do something
}, false);
btn.addEventListener('click',function(){
// do something else
}, false);
当按钮被点击时,会按照添加的顺序依次执行这两个匿名函数。
removeEventListener
方法
用于移除通过addEventListener
添加的事件处理程序。需要注意的是,它只能移除具名函数,不能移除匿名函数。例如:
csharp
function fn1(){
// do something
}
function fn2(){
// do something else
}
btn.addEventListener('click',fn1);
btn.addEventListener('click',fn2);
// 移除fn1事件处理程序(假设在合适的时机调用)
btn.removeEventListener('click',fn1);
- IE中的DOM2级事件(
attachEvent
和detachEvent
)
IE8之前的版本只支持事件冒泡,通过attachEvent
添加的事件处理程序只能添加到冒泡阶段。例如:
arduino
btn.attachEvent('click',fn1);
btn.attachEvent('click',fn2);
当用户点击时,click
队列会依次执行fn1
和fn2
,但函数中的this
指向window
对象。类似地,detachEvent
也只能移除具名函数。
(四)事件捕获与事件冒泡
- 事件流概念
事件流描述了页面中接收事件的顺序。IE的事件流是事件冒泡流,而Netscape Communicator的事件流是事件捕获流。DOM2级事件规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。
- 事件捕获阶段
事件捕获从最不具体的节点(如document
)开始,依次向最具体的节点(如被点击的按钮)传播。这为开发者提供了在事件到达目标元素之前拦截事件的机会。例如,当点击页面中的一个<div>
元素时,事件捕获顺序为:<html>
-> <body>
-> <div>
。
- 处于目标阶段
当事件到达实际的目标元素(如被点击的按钮)时,没有捕获与冒泡之分,执行顺序按照事件处理程序的添加顺序决定,先添加先执行。
- 事件冒泡阶段
事件冒泡则是从最具体的目标元素开始,依次向最不具体的节点传播。例如,点击<div>
元素后,事件冒泡顺序为:<div>
-> <body>
-> <html>
-> document
。在这个阶段,可以在父元素上监听子元素的事件,实现事件委托。
- 阻止事件传播
使用stopPropagation
方法可以取消事件在DOM层次中的传播,包括捕获和冒泡事件。例如:
javascript
var list = document.getElementById('myList');
list.addEventListener('click', function(e){
e.stopPropagation();
console.log('list item clicked');
}, false);
当点击列表项时,事件不会冒泡到父元素。在IE中,对应的属性是cancelBubble
,设置为true
即可阻止事件冒泡。需要注意的是,preventDefault
方法只是阻止默认行为,与事件传播无关。例如,阻止链接的默认跳转行为:
javascript
var link = document.getElementById('myLink');
link.addEventListener('click', function(e){
e.preventDefault();
}, false);
(五)事件对象
- DOM0和DOM2中的事件对象
DOM0和DOM2的事件处理程序都会自动传入event
对象,该对象包含了许多有用的属性和方法,用于获取事件的相关信息,如事件类型、目标元素等。
- IE中的事件对象
在IE中,事件对象取决于指定的事件处理程序的方法。IE的事件处理程序会在全局作用域运行,this
指向window
对象,所以会有window.event
。并且,只有在事件处理程序期间,event
对象才会存在,一旦执行完成,就会被销毁。
- 事件对象的重要属性
target
属性永远指向被添加了事件的那个元素,例如:
javascript
document.body.addEventListener('click', function(e){
console.log(e.target); // 输出被点击的元素
}, false);
eventPhase
属性表示调用事件处理程序的阶段,有三个值:1(捕获阶段)、2(处于目标)、3(冒泡阶段)。例如:
javascript
document.body.addEventListener('click', function(e){
console.log(e.eventPhase); // 根据点击时的阶段输出相应的值
}, false);
(六)事件委托
- 概念与优势
事件委托是一种利用事件冒泡机制来处理多个子元素事件的技术。它的主要优势在于可以减少事件处理程序的数量,提高性能,并且方便管理和更新事件处理逻辑。例如,在一个包含多个列表项的<ul>
元素中,如果为每个列表项都添加一个点击事件处理程序,会导致代码冗余且难以维护。而使用事件委托,只需在父元素(<ul>
)上添加一个点击事件处理程序,然后根据事件的目标元素来判断具体是哪个子元素被点击,从而执行相应的操作。
- 实现方式与示例
假设页面中有一个<ul>
元素,包含多个<li>
子元素:
bash
<ul id="myLinks">
<li id="sayHi">Say hi</li>
<li id="goSomewhere">Go somewhere</li>
<li id="doSomething">Do something</li>
</ul>
使用事件委托来处理列表项的点击事件:
ini
var list = document.getElementById('myLinks');
list.addEventListener('click', function(e){
e = EventUtil.getEvent(e);
var target = EventUtil.getTarget(e);
switch(target.id){
case "goSomewhere":
location.href = "http://www.example.com";
break;
case "doSomething":
document.title = "I changed the document's title";
break;
case "sayHi":
alert("hi");
break;
}
}, false);
这里通过EventUtil
工具函数(可以根据文档中的定义自行实现)来获取事件对象和目标元素,然后根据目标元素的id
执行相应的操作。这样,无论列表中有多少个项目,都只需一个事件处理程序即可处理所有的点击事件。
二、浏览器请求
(一)Ajax
- 概念与特性
Ajax(Asynchronous JavaScript And XML)是一种用于在浏览器端异步发送网络请求的技术,它允许页面在不重新加载整个页面的情况下更新部分内容,实现局部刷新。其重要特性包括异步通信、提高页面响应速度和改善用户体验等。
- 手写Ajax实现步骤
创建异步对象 :根据浏览器的支持情况,使用XMLHttpRequest
或ActiveXObject
创建异步对象。例如:
ini
let xmlHttp;
if (window.XMLHttpRequest) {
xmlHttp = new XMLHttpRequest();
} else {
xmlHttp = new ActiveXObject('Microsoft.XMLHTTP');
}
设置请求方式和请求地址 :使用open
方法设置请求类型(如GET
或POST
)、请求的文件地址和是否异步(通常为true
)。需要注意IE中的缓存问题,对于GET
请求,可以在地址后面拼接随机数或时间戳来避免缓存,如:
vbscript
xmlHttp.open("GET","ajax-get.txt?t=" + (new Date().getTime()),true);
发送请求 :通过send
方法发送请求。如果是POST
请求,需要使用setRequestHeader
设置请求头,并在send
方法中传递要发送的数据,例如:
kotlin
xmlHttp.open("POST","ajax_test.html",true);
xmlHttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlHttp.send("fname=Henry&lname=Ford");
监听状态变化 :通过onreadystatechange
事件监听异步对象的状态变化。当readyState
变为4且http
状态码在200到300之间(包括200和300)或为304时,表示请求成功,可以获取并处理返回的数据;否则,表示请求失败。例如:
lua
xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState === 4) {
if (xmlHttp.status >= 200 && xmlHttp.status < 300 || xmlHttp.status == 304) {
console.log("成功的接收到服务器返回的数据");
console.log(xmlHttp.responseText);
} else {
console.log("不成功!");
}
}
};
处理返回结果 :成功时,可以通过responseText
(获取字符串形式的响应数据)或responseXML
(获取XML形式的响应数据)属性获取服务器返回的数据。在封装ajax
方法时,还需要考虑转码和设置超时时间等问题,例如:
ini
const ajax = option => {
const objToString = data => {
// 处理obj,将数据转码
data.t = new Date().getTime();
let res = [];
for (let key in data) {
res.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]));
}
return res.join('&');
};
let str = objToString(option.data || {});
// 创建异步对象等其他步骤...
xmlHttp.onreadystatechange = function () {
clearInterval(timer);
if (xmlHttp.readyState === 4) {
if ((xmlHttp.status >= 200 && xmlHttp.status < 300) || xmlHttp.status == 304) {
option.success(xmlHttp.responseText);
} else {
option.error(xmlHttp.responseText);
}
}
};
// 判断外界是否传入了超时时间
if (option.timeout) {
timer = setInterval(function () {
xmlHttp.abort();
clearInterval(timer);
}, option.timeout);
}
};
(二)Fetch
- 与Ajax的区别和优势
Fetch是在ES6出现的,它使用了Promise对象,是XMLHttpRequest
的替代品。与传统的Ajax(使用XMLHttpRequest
实现)相比,Fetch具有以下优势:
使用Promise,不使用回调函数,大大简化了写法,使代码更简洁易读。 采用模块化设计,API分散在多个对象上(如Response对象、Request对象、Headers对象),更合理,相比之下,XMLHttpRequest
的API设计容易导致代码混乱。 通过数据流(Stream对象)处理数据,可以分块读取,有利于提高网站性能表现,减少内存占用,尤其适用于请求大文件或网速慢的场景,而XMLHTTPRequest
对象不支持数据流,必须等待全部数据获取后才能处理。
- 基本用法与示例
Fetch的基本用法是fetch(url)
,它接受一个URL字符串作为参数,默认向该网址发出GET
请求,返回一个Promise对象。例如:
ini
fetch('https://api.github.com/users/ruanyf')
.then(response => response.json())
.then(json => console.log(json))
.catch(err => console.log('Request Failed', err));
这里,fetch
返回的response
是一个Stream
对象,需要使用response.json()
等方法来读取响应内容并将其转换为合适的数据类型(如JSON对象)。可以使用await
语法改写,使语义更清晰:
javascript
async function getJSON() {
let url = 'https://api.github.com/users/ruanyf';
try {
let response = await fetch(url);
return await response.json();
} catch (error) {
console.log('Request Failed', error);
}
}
- Response对象的属性和方法
同步属性:
response.status
:返回HTTP回应的状态码(如200表示成功请求)。 response.statusText
:返回HTTP回应的状态信息(如请求成功后,服务器返回"OK")。 response.url
:返回请求的URL,如果存在跳转,返回最终的URL。 response.type
:返回请求的类型,如basic
(普通请求,即同源请求)、cors
(跨域请求)等。 response.redirected
:返回一个布尔值,表示请求是否发生过跳转。
判断请求是否成功 :可以通过response.status
属性判断请求是否成功,只有状态码在200到299之间才认定请求成功,或者使用response.ok
属性(返回布尔值)来判断,例如:
javascript
async function fetchText() {
let response = await fetch('/readme.txt');
if (response.status >= 200 && response.status < 300) {
return await response.text();
} else {
throw new Error(response.statusText);
}
}
Response.headers
属性 :指向一个Headers
对象,对应HTTP回应的所有标头。可以使用for...of
循环遍历标头,Headers
对象还提供了一系列方法来操作标头,如get
(获取指定键名的值)、has
(判断是否包含某个标头)、set
(设置标头)等。例如:
javascript
const response = await fetch(url);
for (let [key, value] of response.headers) {
console.log(`${key} : ${value}`);
}
读取内容的方法:
response.text()
:用于获取文本数据,如HTML文件,返回一个Promise对象,解析完成后得到文本字符串。例如:
ini
const response = await fetch('/users.html');
const body = await response.text();
document.body.innerHTML = body;
javascript
`response.json()`:主要用于获取服务器返回的JSON数据,同样返回Promise对象,解析后得到JSON对象。例如:
ini
const response = await fetch('/article/fetch/post/user');
const json = await response.json();
console.log(json);
go
`response.blob()`:用于获取二进制文件,如图片等。例如:
ini
const response = await fetch('flower.jpg');
const myBlob = await response.blob();
const objectURL = URL.createObjectURL(myBlob);
const myImage = document.querySelector('img');
myImage.src = objectURL;
javascript
`response.formData()`:主要用在Service Worker里面,拦截用户提交的表单,修改某些数据以后,再提交给服务器。
`response.arrayBuffer()`:用于获取二进制ArrayBuffer对象,例如获取音频文件并播放:
ini
const audioCtx = new window.AudioContext();
const source = audioCtx.createBufferSource();
const response = await fetch('song.ogg');
const buffer = await response.arrayBuffer();
const decodeData = await audioCtx.decodeAudioData(buffer);
source.buffer = buffer;
source.connect(audioCtx.destination);
source.loop = true;
Response.clone
方法 :由于Stream
对象只能读取一次,读取完就没了,所以如果需要多次读取响应内容,可以使用Response.clone
方法创建Response
对象的副本。例如:
ini
const response1 = await fetch('flowers.jpg');
const response2 = response1.clone();
const myBlob1 = await response1.blob();
const myBlob2 = await response2.blob();
image1.src = URL.createObjectURL(myBlob1);
image2.src = URL.createObjectURL(myBlob2);
Response.body
属性:它可以用来分块读取内容,应用之一就是显示下载的进度。例如:
javascript
const response = await fetch('flower.jpg');
const reader = response.body.getReader();
while(true) {
const {done, value} = await reader.read();
if (done) {
break;
}
console.log(`Received ${value.length} bytes`);
}
- 定制HTTP请求
fetch
的第一个参数是URL,还可以接受第二个参数作为配置对象,定制发出的HTTP请求。例如:
css
fetch(url, {
method: 'POST',
headers: {
"Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
},
body: 'foo=bar&lorem=ipsum'
})
.then(response => response.json())
.then(json => console.log(json));
配置对象可以设置请求的方法(method
)、标头(headers
)、数据体(body
)等。需要注意的是,有些标头不能通过headers
属性设置,如Cookie
、Host
等,它们是由浏览器自动生成的。 POST请求 :在上面的示例中,通过设置method
为POST
,并指定Content-type
标头和请求体,实现了一个POST请求。 提交JSON数据 :当提交JSON数据时,需要将Content-Type
标头设为application/json;charset=utf-8
,并使用JSON.stringify
将数据转换为字符串。例如:
css
const user = { name: 'John', surname: 'Smith' };
fetch('/article/fetch/post/user', {
method: 'POST',
headers: {
"Content-Type": "application/json;charset=utf-8"
},
body: JSON.stringify(user)
})
.then(response => response.json())
.then(json => console.log(json));
提交表单 :可以直接将FormData
对象作为body
参数提交表单。例如:
ini
const form = document.querySelector('form');
fetch('/users', {
method: 'POST',
body: new FormData(form)
})
.then(response => response.json())
.then(json => console.log(json));
文件上传 :如果表单中有文件选择器,可以将整个表单提交来上传文件,也可以用脚本构造FormData
对象进行上传。例如:
ini
const input = document.querySelector('input[type="file"]');
const data = new FormData();
data.append('file', input.files[0]);
data.append('user', 'foo');
fetch('/avatars', {
method: 'POST',
body: data
})
.then(response => response.json())
.then(json => console.log(json));
直接上传二进制数据 :可以将Blob
或arrayBuffer
数据放在body
属性里面进行上传。例如:
javascript
let blob = await new Promise(resolve => canvasElem.toBlob(resolve, 'image/png'));
fetch('/article/fetch/post/image', {
method: 'POST',
body: blob
})
.then(response => response.json())
.then(json => console.log(json));
option API
fetch
第二个参数的完整API如下:
php
fetch(url, {
method: "GET",
headers: {
"Content-Type": "text/plain;charset=UTF-8"
},
body: undefined,
mode: "cors",
referrer: "about:client",
referrerPolicy: "no-referrer-when-downgrade",
credentials: "same-origin",
cache: "default",
integrity: "",
keepalive: false,
signal: undefined,
redirect: "follow"
})
各属性含义如下:
cache
:指定如何处理缓存,取值有default
(默认值,先在缓存中寻找匹配请求)、no-store
(直接请求远程服务器,不更新缓存)、reload
(直接请求远程服务器并更新缓存)、no-cache
(比较服务器资源和本地缓存,有新的版本才使用服务器资源,否则使用缓存)、force-cache
(缓存优先,只有不存在缓存时才请求远程服务器)、only-if-cached
(只检查缓存,如果不存在则返回504错误)。mode
:指定请求的模式,取值有cors
(默认值,允许跨域请求)、same-origin
(只允许同源请求)、no-cors
(请求方法限于GET、POST和HEAD,只能使用有限的几个简单标头,不能添加自定义标头,跨域请求时不发送Cookie等)。 -credentials
:指定是否发送Cookie,取值有same-origin
(默认值,同源请求时发送Cookie,跨域请求时不发送)、include
(不管同源还是跨域请求,一律发送Cookie)、omit
(一律不发送)。signal
:指定一个AbortSignal
实例,用于取消fetch
请求。keepalive
:用于页面卸载时,告诉浏览器在后台保持连接继续发送数据,典型场景是用户离开网页时提交统计信息。redirect
:指定HTTP跳转的处理方法,取值有follow
(默认值,fetch
跟随HTTP跳转)、error
(如果发生跳转,fetch
报错)、manual
(fetch
不跟随HTTP跳转,但response.url
属性会指向新的URL,response.redirected
属性变为true
,由开发者决定后续处理)。integrity
:指定一个哈希值,用于检查HTTP回应传回的数据是否等于预先设定的哈希值,例如下载文件时检查文件的SHA - 256哈希值是否相符,确保文件未被篡改。referrer
:用于设定fetch
请求的referer
标头,可以为任意字符串或空字符串(不发送referer
标头)。referrerPolicy
:用于设定Referer
标头的规则,取值有no-referrer-when-downgrade
(默认值,总是发送Referer
标头,除非从HTTPS页面请求HTTP资源时不发送)、no-referrer
(不发送Referer
标头)、origin
(Referer
标头只包含域名,不包含完整路径)、origin-when-cross-origin
(同源请求Referer
标头包含完整路径,跨域请求只包含域名)、same-origin
(跨域请求不发送Referer
,同源请求发送)、strict-origin-when-cross-origin
(同源请求时Referer
标头包含完整路径,跨域请求时只包含域名,HTTPS页面请求HTTP资源时不发送该标头)、unsafe-url
(不管什么情况,总是发送Referer
标头)。
fetch cancel
fetch
请求发送后,如果中途想要取消,需要使用AbortController
对象。例如:
ini
let controller = new AbortController();
let signal = controller.signal;
fetch(url, { signal: controller.signal });
signal.addEventListener('abort', () => console.log('abort!'));
controller.abort();
console.log(signal.aborted); // true
首先创建AbortController
实例,获取其signal
属性并在fetch
请求中配置。然后通过controller.abort
方法发出取消信号,此时会触发abort
事件,可以监听该事件,也可以通过signal.aborted
属性判断取消信号是否已发出。例如,1秒后自动取消请求:
javascript
let controller = new AbortController();
setTimeout(() => controller.abort(), 1000);
try {
let response = await fetch('/long-operation', { signal: controller.signal });
console.log(response);
} catch(err) {
if (err.name == 'AbortError') {
console.log('Aborted!');
} else {
throw err;
}
}
(三)Axios
- 特点与优势
Axios是一个用于网络请求的第三方库,基于Promise,可用于浏览器和Node.js。它具有以下特点和优势:
从浏览器中创建XMLHttpRequest
,从Node.js发出http请求,具有广泛的适用性。 支持Promise API,使得请求处理更加简洁和易于管理,能够有效避免回调地狱。 可以拦截请求和响应,方便在请求发送前和响应返回后进行统一的处理,如添加请求头、处理错误等。 自动转换JSON数据,无需手动解析,提高开发效率。 客户端支持防止CSRF/XSRF攻击,增强应用的安全性。
- 基础使用
axios(config)
方法 :接收一个包含请求配置的对象,基本配置项包括method
(请求方法,可选值如get
、post
等,默认是get
)、url
(请求地址,必须项)、data
(请求发送的数据,post
等请求需要)。例如:
php
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
})
.then(res => console.log(res))
.catch(err => console.log(err));
请求响应的处理在then
和catch
回调中,请求正常进入then
,异常则进入catch
。 请求别名 :Axios提供了一些请求别名,如axios.get
、axios.post
等,使用更加便捷。例如:
javascript
axios.get('/user?ID=12345')
.then(response => console.log(response))
.catch(error => console.log(error));
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(response => console.log(response))
.catch(error => console.log(error));
- 响应数据
响应数据包含多个字段,其中data
是后端返回的数据,一般主要关注response
中的data
字段。例如:
vbscript
axios.get('/user/12345')
.then(response => {
console.log(response.data);
})
.catch(error => console.log(error));
完整的响应对象还包括status
(服务器响应的HTTP状态码)、statusText
(服务器响应的HTTP状态信息)、headers
(服务器响应的头)、config
(为请求提供的配置信息)、request
(生成此响应的请求对象,在浏览器中是XMLHttpRequest
实例,在Node.js中是ClientRequest
实例)。
- 创建实例
可以使用axios.create([config])
创建自定义配置的Axios实例,创建的实例中的axios()
方法改为了request()
方法,使用方式相同,其他如请求别名等函数也不变。例如:
javascript
const instance = axios.create({
headers: {'X-Custom-Header': 'foobar'},
baseURL: 'https://some-domain.com/api/',
timeout: 1000
});
instance.get('/user/12345')
.then(response => console.log(response))
.catch(error => console.log(error));
- 拦截器
请求拦截器 :使用axios.interceptors.request.use
添加请求拦截器,在发送请求之前可以对请求进行统一处理,如添加请求头、修改请求数据等。例如:
lua
axios.interceptors.request.use(function (config) {
config.headers["Token"] = "xxxx";
return config;
}, function (error) {
return Promise.reject(error);
});
响应拦截器 :使用axios.interceptors.response.use
添加响应拦截器,在响应返回后可以对响应数据进行处理,如根据状态码进行不同的操作。例如:
javascript
axios.interceptors.response.use(function (response) {
if (response.status === 200){
return response.data;
} else {
return Promise.reject(new Error('error'));
}
}, function (error) {
return Promise.reject(error);
});
如果想要取消拦截器,可以通过变量接收设置拦截器时返回的实例,然后使用eject
方法取消。例如:
php
const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
- 完整的请求配置
Axios的完整请求配置包含众多选项,除了前面提到的method
、url
、data
等基本配置外,还包括:
transformRequest
:允许在向服务器发送前修改请求数据,只能用于PUT
、POST
和PATCH
请求方法,函数必须返回字符串、ArrayBuffer或Stream。transformResponse
:在传递给then/catch
前允许修改响应数据。headers
:自定义请求头。params
:与请求一起发送的URL参数,必须是无格式对象或URLSearchParams
对象。paramsSerializer
:负责params
序列化的函数。timeout
:指定请求超时的毫秒数(0表示无超时时间)。withCredentials
:表示跨域请求时是否使用凭证。adapter
:允许自定义处理请求,用于测试等场景。auth
:用于HTTP基础验证,设置Authorization
头。responseType
:服务器响应的数据类型,如arraybuffer
、blob
、document
、json
、text
、stream
等。responseEncoding
:用于解码响应的编码。xsrfCookieName
和xsrfHeaderName
:用于处理XSRF令牌。onUploadProgress
和onDownloadProgress
:分别用于处理上传和下载的进度事件。validateStatus
:定义对于给定的HTTP响应状态码是resolve
还是reject
Promise。maxContentLength
:定义允许的响应内容的最大尺寸。maxRedirects
:定义在Node.js中跟随的最大重定向数目。socketPath
和proxy
:用于在Node.js中定义请求的相关路径和代理。cancelToken
:指定用于取消请求的cancel token
。
(四)总结与对比
- Ajax
Ajax是原生JavaScript的一种请求方案,利用XMLHttpRequest
进行异步请求数据,实现页面的局部刷新,是早期前端开发中常用的网络请求方式。然而,它的API相对复杂,使用回调函数处理异步操作容易导致回调地狱,代码可读性和维护性较差。但在一些不支持较新特性的项目中,或者对兼容性要求较高的场景下,仍然可能会使用到Ajax。
- Fetch
Fetch是ES6新推出的异步请求方案,基于Promise,具有简洁的语法和模块化的设计。它通过数据流处理数据,在性能和内存管理方面有一定优势,适用于现代浏览器环境下的项目开发。但Fetch在处理请求错误和兼容性方面存在一些问题,例如它默认不会对4xx和5xx状态码的响应进行错误处理,需要开发者手动判断。此外,在一些旧版本浏览器中可能需要使用polyfill来实现兼容