跳到主要内容

请求处理

实现⼀个简易的axios?

function simpleAxios(url, options = {}) {
// 默认配置
const defaultOptions = {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
};

// 合并默认配置和用户提供的配置
const mergedOptions = { ...defaultOptions, ...options };

// 使用fetch发起请求
return fetch(url, mergedOptions)
.then(response => {
// 检查响应状态码
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
// 根据响应类型解析数据
if (mergedOptions.responseType === 'json') {
return response.json();
} else if (mergedOptions.responseType === 'text') {
return response.text();
} else {
return response;
}
})
.catch(error => {
// 处理请求错误
console.error('Request failed:', error);
throw error;
});
}

// 使用示例
simpleAxios('https://api.example.com/data', {
method: 'POST',
headers: {
'Authorization': 'Bearer your-token'
},
body: JSON.stringify({ key: 'value' }),
responseType: 'json'
}).then(data => {
console.log('Success:', data);
}).catch(error => {
console.error('Error:', error);
});

对axios进⾏⼆次封装的好处。

  • 统一的请求配置:为所有的 API 请求设置统一的配置,如请求头、超时时间、基础 URL 等。

  • 封装可以包含统一的错误处理逻辑,如自动处理网络错误、超时错误、HTTP 错误等,

  • 封装可以添加请求拦截器和响应拦截器,用于在请求发送前和响应返回后执行一些操作,如添加认证令牌、处理响应数据等。

  • 代码复用:可以被多个组件或服务共享,避免了重复的代码编写,提高了代码的复用性。

  • 便于维护和扩展:封装后的 Axios 实例可以集中管理,便于维护和扩展。

  • 安全性:封装可以包含安全相关的逻辑,如自动处理 CSRF 令牌、防止跨站请求伪造等,提高应用的安全性。

  • 便于测试 封装后的 Axios 实例可以更容易地进行单元测试和集成测试,因为请求和响应的处理逻辑被封装在一个独立的模块中。

  • 使得项目的结构更加清晰,便于其他开发者理解和维护。

以下是一个简单的 Axios 二次封装示例:

import axios from 'axios';

// 创建一个 Axios 实例
const apiClient = axios.create({
baseURL: 'https://api.example.com',
timeout: 10000,
headers: {
'Content-Type': 'application/json',
},
});

// 请求拦截器
apiClient.interceptors.request.use(
config => {
// 在发送请求之前做些什么
return config;
},
error => {
// 对请求错误做些什么
return Promise.reject(error);
}
);

// 响应拦截器
apiClient.interceptors.response.use(
response => {
// 对响应数据做点什么
return response;
},
error => {
// 对响应错误做点什么
return Promise.reject(error);
}
);

export default apiClient;

如何实现简单的hash路由

const routes = {};

function registerRoute(path, handler) {
routes[path] = handler;
}

function navigate(path) {
if (routes[path]) {
routes[path]();
} else {
console.log('Route not found');
}
}

// 注册路由
registerRoute('/page1', () => {
console.log('This is page1');
});

registerRoute('/page2', () => {
console.log('This is page2');
});

// 进行路由导航
navigate('/page1');
navigate('/page2');

请求失败会弹出一个 toast,如何保证批量请求失败,只弹出一个 toast?

  • 解决方案

    • 使用防抖(debounce)或节流(throttle)技术,延迟 toast 的显示。

    • 在全局状态中记录是否已经显示过 toast,避免重复显示。

    • 示例:

      let isToastShown = false;
      function showToast() {
      if (!isToastShown) {
      isToastShown = true;
      Toast.show("请求失败");
      setTimeout(() => { isToastShown = false; }, 3000); // 3秒后重置
      }
      }

如何解决页面请求接口大规模并发问题?

  • 解决方案
    • 使用 Promise.all 并发请求。
    • 设置请求队列,限制并发数。
    • 使用缓存(如 Redis)减少重复请求。

写道题(这个题意我都没听懂),传入一个并发池和一个并发数,并发池的每一项都是promise,要求返回值是按并发池的顺序的

function promisePool(promises, concurrency) {
return new Promise((resolve, reject) => {
let index = 0; // 当前处理的 Promise 的索引
const results = []; // 用来存储按顺序返回的结果
let activeCount = 0; // 当前正在执行的 Promise 数量

// 执行下一个 Promise 的函数
const executeNext = () => {
// 如果所有 Promise 都执行完了,就返回结果
if (index === promises.length && activeCount === 0) {
resolve(results);
return;
}

// 只要有空闲的并发位置,继续执行 Promise
if (activeCount < concurrency && index < promises.length) {
const currentIndex = index++; // 保存当前 Promise 的索引
activeCount++; // 增加当前活动的 Promise 数量

promises[currentIndex]
.then((result) => {
results[currentIndex] = result; // 根据索引保存结果
})
.catch((error) => {
results[currentIndex] = error; // 捕获错误,保留错误信息
})
.finally(() => {
activeCount--; // 完成后减少活动的 Promise 数量
executeNext(); // 执行下一个 Promise
});

// 递归调用,保证每次都有任务执行
executeNext();
}
};

// 初始化执行
executeNext();
});
}



const promise1 = new Promise(resolve => setTimeout(() => resolve('Result 1'), 1000));
const promise2 = new Promise(resolve => setTimeout(() => resolve('Result 2'), 500));
const promise3 = new Promise(resolve => setTimeout(() => resolve('Result 3'), 300));
const promise4 = new Promise(resolve => setTimeout(() => resolve('Result 4'), 200));
const promise5 = new Promise(resolve => setTimeout(() => resolve('Result 5'), 400));

const promises = [promise1, promise2, promise3, promise4, promise5];

promisePool(promises, 2)
.then(results => {
console.log(results);
// 输出按顺序的结果,比如:['Result 1', 'Result 2', 'Result 3', 'Result 4', 'Result 5']
})
.catch(err => console.error(err));