深入探索前端开发中的浏览器事件模型与请求处理

深入探索前端开发中的浏览器事件模型与请求处理

我敬佩简单的快乐,那是复杂最后的避难所。 ---奥斯卡·王尔德-

在前端开发领域,浏览器事件模型和请求处理是构建交互性强、高性能网页应用的核心要素。作为前端开发者,深入理解这些概念并熟练运用相关技术,对于打造优质用户体验至关重要。在这篇文章中,我们将全面且深入地探讨浏览器事件模型、事件委托、浏览器请求(包括 Ajax、Fetch 和 Axios)等重要主题,为前端开发者提供详尽的知识储备和实践指导。

一、浏览器事件模型

(一)DOM事件概述

DOM(文档对象模型)是针对HTML和XML文档的API,它提供了一种结构化的方式来表示和操作页面内容。DOM事件则是用户或浏览器在文档上执行的操作,如点击、加载、鼠标移动等,开发者可以通过JavaScript代码来响应这些事件。

(二)DOM0级事件

  1. 基本使用方式

在DOM0级事件模型中,事件处理程序直接绑定在元素的属性上。例如,给一个按钮添加点击事件:

ini 复制代码
var btn = document.getElementById('btn');
btn.onclick = function(){
    console.log('this is a click event');
}

这里,onclick是按钮元素的一个属性,将一个函数赋值给它,当按钮被点击时,该函数就会被执行。

  1. 事件处理程序中的 this指向

在非严格模式下,如果指定的this值为nullundefined,它会自动指向全局对象(在浏览器中为window对象);若this值为原始值(数字、字符串、布尔值),则会指向该原始值的自动包装对象。例如:

javascript 复制代码
btn.onclick = function(){
    console.log(this === window); // 在非严格模式下,输出为true
}

但在严格模式下,this的值保持不变,不会自动指向全局对象。

  1. 事件对象 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中访问事件对象
}
  1. 绑定多个事件处理程序

要为一个对象绑定多个函数,可以在事件处理程序中依次调用这些函数,例如:

javascript 复制代码
function fn1(){
    // do something
}
function fn2(){
    // do something
}
btn.onclick = function(e){
    fn1.call(this);
    fn2.call(this);
}

这里通过call方法来确保函数中的this指向正确的对象(即按钮元素)。

(三)DOM2级事件

  1. 事件模型特点

DOM2级事件将属性升级为队列,通过addEventListenerremoveEventListener方法来添加和移除事件处理程序。这使得一个元素可以绑定多个相同类型的事件处理程序,并且可以控制事件在捕获阶段或冒泡阶段执行。

  1. addEventListener方法

该方法接收三个参数:要处理的事件名、作为事件处理程序的函数、一个布尔值(true代表在捕获阶段调用事件处理程序,false表示在冒泡阶段调用,默认值为false)。例如:

lua 复制代码
btn.addEventListener('click',function(){
    // do something
}, false);
btn.addEventListener('click',function(){
    // do something else
}, false);

当按钮被点击时,会按照添加的顺序依次执行这两个匿名函数。

  1. 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);
  1. IE中的DOM2级事件( attachEvent detachEvent

IE8之前的版本只支持事件冒泡,通过attachEvent添加的事件处理程序只能添加到冒泡阶段。例如:

arduino 复制代码
btn.attachEvent('click',fn1);
btn.attachEvent('click',fn2);

当用户点击时,click队列会依次执行fn1fn2,但函数中的this指向window对象。类似地,detachEvent也只能移除具名函数。

(四)事件捕获与事件冒泡

  1. 事件流概念

事件流描述了页面中接收事件的顺序。IE的事件流是事件冒泡流,而Netscape Communicator的事件流是事件捕获流。DOM2级事件规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。

  1. 事件捕获阶段

事件捕获从最不具体的节点(如document)开始,依次向最具体的节点(如被点击的按钮)传播。这为开发者提供了在事件到达目标元素之前拦截事件的机会。例如,当点击页面中的一个<div>元素时,事件捕获顺序为:<html> -> <body> -> <div>

  1. 处于目标阶段

当事件到达实际的目标元素(如被点击的按钮)时,没有捕获与冒泡之分,执行顺序按照事件处理程序的添加顺序决定,先添加先执行。

  1. 事件冒泡阶段

事件冒泡则是从最具体的目标元素开始,依次向最不具体的节点传播。例如,点击<div>元素后,事件冒泡顺序为:<div> -> <body> -> <html> -> document。在这个阶段,可以在父元素上监听子元素的事件,实现事件委托。

  1. 阻止事件传播

使用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);

(五)事件对象

  1. DOM0和DOM2中的事件对象

DOM0和DOM2的事件处理程序都会自动传入event对象,该对象包含了许多有用的属性和方法,用于获取事件的相关信息,如事件类型、目标元素等。

  1. IE中的事件对象

在IE中,事件对象取决于指定的事件处理程序的方法。IE的事件处理程序会在全局作用域运行,this指向window对象,所以会有window.event。并且,只有在事件处理程序期间,event对象才会存在,一旦执行完成,就会被销毁。

  1. 事件对象的重要属性

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);

(六)事件委托

  1. 概念与优势

事件委托是一种利用事件冒泡机制来处理多个子元素事件的技术。它的主要优势在于可以减少事件处理程序的数量,提高性能,并且方便管理和更新事件处理逻辑。例如,在一个包含多个列表项的<ul>元素中,如果为每个列表项都添加一个点击事件处理程序,会导致代码冗余且难以维护。而使用事件委托,只需在父元素(<ul>)上添加一个点击事件处理程序,然后根据事件的目标元素来判断具体是哪个子元素被点击,从而执行相应的操作。

  1. 实现方式与示例

假设页面中有一个<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

  1. 概念与特性

Ajax(Asynchronous JavaScript And XML)是一种用于在浏览器端异步发送网络请求的技术,它允许页面在不重新加载整个页面的情况下更新部分内容,实现局部刷新。其重要特性包括异步通信、提高页面响应速度和改善用户体验等。

  1. 手写Ajax实现步骤

创建异步对象 :根据浏览器的支持情况,使用XMLHttpRequestActiveXObject创建异步对象。例如:

ini 复制代码
let xmlHttp;
if (window.XMLHttpRequest) {
    xmlHttp = new XMLHttpRequest();
} else {
    xmlHttp = new ActiveXObject('Microsoft.XMLHTTP');
}

设置请求方式和请求地址 :使用open方法设置请求类型(如GETPOST)、请求的文件地址和是否异步(通常为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

  1. 与Ajax的区别和优势

Fetch是在ES6出现的,它使用了Promise对象,是XMLHttpRequest的替代品。与传统的Ajax(使用XMLHttpRequest实现)相比,Fetch具有以下优势:

使用Promise,不使用回调函数,大大简化了写法,使代码更简洁易读。 采用模块化设计,API分散在多个对象上(如Response对象、Request对象、Headers对象),更合理,相比之下,XMLHttpRequest的API设计容易导致代码混乱。 通过数据流(Stream对象)处理数据,可以分块读取,有利于提高网站性能表现,减少内存占用,尤其适用于请求大文件或网速慢的场景,而XMLHTTPRequest对象不支持数据流,必须等待全部数据获取后才能处理。

  1. 基本用法与示例

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);
    }
}
  1. 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`);
}
  1. 定制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属性设置,如CookieHost等,它们是由浏览器自动生成的。 POST请求 :在上面的示例中,通过设置methodPOST,并指定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));

直接上传二进制数据 :可以将BlobarrayBuffer数据放在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));
  1. 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报错)、manualfetch不跟随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标头)、originReferer标头只包含域名,不包含完整路径)、origin-when-cross-origin(同源请求Referer标头包含完整路径,跨域请求只包含域名)、same-origin(跨域请求不发送Referer,同源请求发送)、strict-origin-when-cross-origin(同源请求时Referer标头包含完整路径,跨域请求时只包含域名,HTTPS页面请求HTTP资源时不发送该标头)、unsafe-url(不管什么情况,总是发送Referer标头)。
  1. 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

  1. 特点与优势

Axios是一个用于网络请求的第三方库,基于Promise,可用于浏览器和Node.js。它具有以下特点和优势:

从浏览器中创建XMLHttpRequest,从Node.js发出http请求,具有广泛的适用性。 支持Promise API,使得请求处理更加简洁和易于管理,能够有效避免回调地狱。 可以拦截请求和响应,方便在请求发送前和响应返回后进行统一的处理,如添加请求头、处理错误等。 自动转换JSON数据,无需手动解析,提高开发效率。 客户端支持防止CSRF/XSRF攻击,增强应用的安全性。

  1. 基础使用

axios(config)方法 :接收一个包含请求配置的对象,基本配置项包括method(请求方法,可选值如getpost等,默认是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));

请求响应的处理在thencatch回调中,请求正常进入then,异常则进入catch请求别名 :Axios提供了一些请求别名,如axios.getaxios.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));
  1. 响应数据

响应数据包含多个字段,其中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实例)。

  1. 创建实例

可以使用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));
  1. 拦截器

请求拦截器 :使用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);
  1. 完整的请求配置

Axios的完整请求配置包含众多选项,除了前面提到的methodurldata等基本配置外,还包括:

  • transformRequest:允许在向服务器发送前修改请求数据,只能用于PUTPOSTPATCH请求方法,函数必须返回字符串、ArrayBuffer或Stream。
  • transformResponse:在传递给then/catch前允许修改响应数据。
  • headers:自定义请求头。
  • params:与请求一起发送的URL参数,必须是无格式对象或URLSearchParams对象。
  • paramsSerializer:负责params序列化的函数。
  • timeout:指定请求超时的毫秒数(0表示无超时时间)。
  • withCredentials:表示跨域请求时是否使用凭证。
  • adapter:允许自定义处理请求,用于测试等场景。
  • auth:用于HTTP基础验证,设置Authorization头。
  • responseType:服务器响应的数据类型,如arraybufferblobdocumentjsontextstream等。
  • responseEncoding:用于解码响应的编码。
  • xsrfCookieNamexsrfHeaderName:用于处理XSRF令牌。
  • onUploadProgressonDownloadProgress:分别用于处理上传和下载的进度事件。
  • validateStatus:定义对于给定的HTTP响应状态码是resolve还是reject Promise。
  • maxContentLength:定义允许的响应内容的最大尺寸。
  • maxRedirects:定义在Node.js中跟随的最大重定向数目。
  • socketPathproxy:用于在Node.js中定义请求的相关路径和代理。
  • cancelToken:指定用于取消请求的cancel token

(四)总结与对比

  1. Ajax

Ajax是原生JavaScript的一种请求方案,利用XMLHttpRequest进行异步请求数据,实现页面的局部刷新,是早期前端开发中常用的网络请求方式。然而,它的API相对复杂,使用回调函数处理异步操作容易导致回调地狱,代码可读性和维护性较差。但在一些不支持较新特性的项目中,或者对兼容性要求较高的场景下,仍然可能会使用到Ajax。

  1. Fetch

Fetch是ES6新推出的异步请求方案,基于Promise,具有简洁的语法和模块化的设计。它通过数据流处理数据,在性能和内存管理方面有一定优势,适用于现代浏览器环境下的项目开发。但Fetch在处理请求错误和兼容性方面存在一些问题,例如它默认不会对4xx和5xx状态码的响应进行错误处理,需要开发者手动判断。此外,在一些旧版本浏览器中可能需要使用polyfill来实现兼容

相关推荐
存梨10 分钟前
2024 年终总结
前端·react.js
咔咔库奇10 分钟前
【react】常见的性能优化 1
前端·react.js·性能优化
️○-12 分钟前
React之从0开始(3)
前端·javascript·react.js
练习两年半的工程师16 分钟前
使用React Redux实现异步请求
前端·javascript·react.js
screct_demo17 分钟前
详细讲一下React中的路由React Router
前端·javascript·react.js
David@35 分钟前
npm install 安装选项 -d -s -g
前端·vue.js·vue
【D'accumulation】37 分钟前
深入聊聊typescript、ES6和JavaScript的关系与前瞻技术发展
java·开发语言·前端·javascript·typescript·es6
亿点鸭梨39 分钟前
vue使用el-select下拉框自定义复选框
前端·javascript·vue.js
创意锦囊44 分钟前
解决 HTML 表单输入框与按钮对齐问题
前端·html
常常不爱学习1 小时前
CSS浮动
前端·css