闭包封装Web API的核心是固化通用配置并隔离状态,通过工厂函数createRequester返回可复用的请求函数,支持默认headers、token自动注入、超时控制及错误处理,还可柯里化实现语义化调用。

闭包封装 Web API 接口,核心是把通用配置“固化”在函数作用域里,让每次调用自动携带,同时隔离内部状态、避免污染全局,还能灵活扩展行为。
闭包封装的关键在于“记住配置,隔离状态”
不是写个函数就叫封装,而是让 baseURL、token、超时、默认 headers 这些不变量,在初始化时存进闭包,后续所有请求都复用它们,不用每次传。
用工厂函数创建带配置的请求器
写一个 createRequester(config),它接收配置对象,内部定义真正发请求的函数,并返回这个函数。该函数能访问 config,但外部无法直接改 config。
function createRequester({ baseURL, headers = {}, timeout = 5000, token }) {
const defaultHeaders = {
'Content-Type': 'application/json',
...headers,
...(token && { Authorization: `Bearer ${token}` })
};
return async function request(path, options = {}) {
const url = new URL(path, baseURL);
const config = {
method: options.method || 'GET',
headers: { ...defaultHeaders, ...options.headers },
signal: options.signal,
...((options.method || 'GET').toUpperCase() !== 'GET' && options.body
? { body: JSON.stringify(options.body) }
: {})
};
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const res = await fetch(url, { ...config, signal: controller.signal });
clearTimeout(timeoutId);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return await res.json();
} catch (err) {
clearTimeout(timeoutId);
if (err.name === 'AbortError') throw new Error('Request timeout');
throw err;
}
};
}生成专用接口,语义清晰又可复用
调用工厂函数,得到专属请求函数,后续只关心业务逻辑:
const api = createRequester({
baseURL: 'https://api.example.com/v1',
token: localStorage.getItem('token')
});
// 直接调用,无需重复写 baseURL 或 token
const user = await api('/users/123');
const list = await api('/posts', { method: 'POST', body: { title: 'Hello' } });支持柯里化,进一步解耦路径与参数
如果想把路径提前绑定,再动态传参,可以加一层柯里化:
function createRequester(config) {
const requester = /* 上面定义的 request 函数 */;
return {
get: (path) => (params) => requester(path + (params ? `?${new URLSearchParams(params)}` : '')),
post: (path) => (body) => requester(path, { method: 'POST', body }),
put: (path) => (body) => requester(path, { method: 'PUT', body })
};
}
const api = createRequester({ baseURL: 'https://api.example.com' });
const fetchUser = api.get('/users'); // 返回函数
const user = await fetchUser({ id: 123 }); // 实际发起 GET /users?id=123注意闭包带来的内存与清理问题
闭包会让 config 和内部变量持续驻留。如果 token 过期或 baseURL 变更,应重新创建 requester;长期运行的页面中,避免把大量数据塞进闭包,必要时手动解除引用(如清空大缓存对象)。
不复杂但容易忽略


















