157期
1. Vue中Scoped Styles 为什么可以实现样式隔离?
2. canvas 和 webgl 有什么区别?
3. 如果空数组调用reduce会发生什么?
上面问题的答案会在第二天的公众号(程序员每日三问)推文中公布
也可以小程序刷题,已收录500+面试题及答案
156期问题及答案
1. POST请求的 Content-Type 常见的有哪几种?
在HTTP POST请求中,Content-Type
是一个非常重要的HTTP头部字段,主要用来指示资源的MIME类型。在进行POST请求时,常见的Content-Type
类型有以下几种:
application/x-www-form-urlencoded
这是最常见的POST请求类型。浏览器的原生表单
<form>
将数据编码为名称/值对时使用这种类型。这种格式对数据进行了URL编码,即将空格转换为+
,特殊字符转换为%XX
的形式。
multipart/form-data
用于当表单中有需要上传的文件时使用。每部分都是由一个由随机的边界字符串分隔的内容块构成的,每部分包含了表单的一个元素。这也是文件上传时使用的编码类型。
application/json
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于读写且易于机器解析和生成。当你需要在POST请求中发送JSON格式的数据时,会使用这个类型。
text/plain
纯文本格式,虽然不常用于API请求,但有时在需要发送一些纯文本内容的时候会用到。
application/xml
或 text/xml
XML(eXtensible Markup Language)格式,当要发送XML格式的内容时使用。
application/xml
用于XML数据的HTTP请求,而text/xml
用于可读的XML数据。
根据不同的需要,选择适合的Content-Type
对于确保HTTP请求顺利进行至关重要。例如,如果需要发送JSON格式的数据,则必须指定Content-Type
为application/json
,以便服务器能够正确解析请求体中的内容。
2. JavaScript 中如何取消请求?
在JavaScript中,可以使用AbortController
接口和它的abort()
方法来取消一个请求。这个功能主要用在fetch
API中,但也可以用于其他基于Promise的API,只要它们支持中断操作。
AbortController
提供了一个控制器对象,可以通过它的signal
属性向一个操作(例如网络请求)发送取消信号。下面是一个如何使用AbortController
来取消fetch
请求的示例:
// 创建一个AbortController实例
const controller = new AbortController();
// 获取AbortSignal对象
const signal = controller.signal;
// 启动fetch请求并传入signal
fetch('http://example.com/api/data', { signal })
.then(response => response.json())
.then(data => console.log(data))
.catch(err => {
if (err.name === 'AbortError') {
console.log('Fetch请求被取消');
} else {
// 处理其他错误
console.log(err);
}
});
// 5秒后取消请求
setTimeout(() => controller.abort(), 5000);
在上面的例子中,我们创建一个AbortController实例和它的signal对象,然后将这个signal对象作为fetch
请求的一个参数。如果我们想要取消这个请求,可以在任意时间调用controller.abort()
方法。在这个例子中,我们设置了一个5秒的定时器,在5秒后调用controller.abort()
来取消请求。
如果取消操作成功完成,fetch
的Promise会被拒绝,并且错误name
属性值为"AbortError"
,这样你就可以通过这个特定的错误类型来捕捉取消操作事件。
需要注意的一点是,AbortController
和fetch
是现代浏览器中新增的功能。对于不支持这些API的旧浏览器,你可能需要使用polyfill或者考虑使用XMLHttpRequest的abort()
方法来实现取消请求的功能。
3. 实现一个批量请求函数,要求能够限制并发量?
下面是使用 JavaScript(基于Promise和async/await语法)实现的一个批量请求函数,该函数支持限制并发请求数量:
function batchRequest(urls, limit) {
// 正在执行的请求数量
let activeCount = 0;
// 使用async函数包装fetch请求
const fetchWithLimit = async (url) => {
// 增加正在执行的请求数量
activeCount++;
try {
const response = await fetch(url); // 执行请求
const data = await response.json(); // 解析结果
return data;
} catch (error) {
throw error;
} finally {
// 请求完成后,减少正在执行的请求数量,并尝试进行下一个请求
activeCount--;
processNext();
}
};
// 将所有URL包装成任务数组
const tasks = urls.map((url) => () => fetchWithLimit(url));
// 创建用来存储所有结果的数组
const results = [];
return new Promise((resolve, reject) => {
// 此函数递归调用,直到所有任务完成
const processNext = () => {
// 所有任务完成时,resolve最终结果
if (tasks.length === 0 && activeCount === 0) {
resolve(results);
return;
}
// 如果当前激活的请求数未达上限,则执行下一个请求
while (activeCount < limit && tasks.length > 0) {
const task = tasks.shift(); // 获取任务队列中的下一个任务
const index = results.length; // 记录当前任务的索引
results.push(task().then((data) => {
// 若请求成功,将结果放到正确的位置
results[index] = data;
return data;
}).catch((error) => {
// 若请求失败,记录错误到相应的位置
results[index] = error;
return error;
}));
}
};
processNext(); // 开始处理队列
});
}
// 使用示例:
// 假设有一个URL数组,希望批量请求,并限制并发数为3
const urls = [
"http://example.com/api/endpoint1",
"http://example.com/api/endpoint2",
// ...更多URLs
];
batchRequest(urls, 3)
.then(results => {
console.log("全部请求完成");
console.log(results);
})
.catch(error => {
console.log("发生错误", error);
});
这个函数的核心逻辑如下:
通过映射输入的URL数组
urls
,创建一个任务数组tasks
,每个任务都是一个返回Promise的函数,用于执行对应URL的请求。使用
activeCount
变量跟踪当前正在执行的请求数。processNext
函数会在请求完成或者请求开启时被调用。它负责开始执行新的请求(只要当前活跃的请求数小于limit
限制,并且tasks
任务队列非空)。当所有的请求都完成时,所有的结果将会返回在一个数组中,无论它们是成功还是失败。成功的请求会在相应的位置保存响应结果,失败的请求会在相应位置保存错误。
通过这种方式,可以确保不会超过设置的并发请求数量limit
,同时高效地执行批量请求。
我要提问
如果你遇到有趣的面试题,或者有想知道的前端面试题,可以在下面的小程序提问,收到问题后会在第一时间为你解答。
我要出题
学习不打烊,充电加油只为遇到更好的自己,每天早上9点纯手工发布面试题,每天坚持花20分钟来学习与思考,在千变万化,类库层出不穷的今天,不要等到找工作时才狂刷题,提倡每日学习。