先说一下为何要造这个轮子javascript
因此决定造一个支持上面功能的轮子html
简单说一下存在的历史,浏览器存在同源政策,即域名+端口+协议必须一致,不少时候咱们须要跨域访问,因此 jsonp 就出现了,固然还有其余方法,可是这里不作科普能够搜索一下跨越解决方法。java
jsonp 的原理就是浏览器的 script
标签能够加载不一样源的资源,配合后端经过执行函数传递参数,这也是 jsonp 只支持 get 的缘由ios
<script> function callback(v) { console.log("参数是:"); console.log(v); } </script>
<script> callback({ name: "zhangsan", age: 18 }); </script>
复制代码
interface Iparams {
[propName: string]: any;
}
interface Ioptions {
params?: Iparams;
timeout?: number;
name?: string;
}
let uid = 0;
const jsonp = function jsonp(this: any, url: string, option: Ioptions = {}) {
return new Promise((resolve, reject) => {
// 注意,这个id不能重复
const id = `__uid${uid++}`;
Reflect.set(window, id, (...rest: any[]) => {
clear();
return resolve.call(this, ...rest);
});
const { name = "callback", params = {}, timeout = 6000 } = option;
// 清理
const clear = () => {
Reflect.set(window, id, () => {});
script.parentNode.removeChild(script);
if (timer) {
clearTimeout(timer);
}
};
// 建立超时任务
let timer: NodeJS.Timeout;
if (typeof timeout === "number") {
timer = setTimeout(() => {
clear();
return reject(new Error(`Task timeout`));
}, timeout);
}
const script: HTMLScriptElement = document.createElement("script");
// 处理一下参数最终合并
const par = new URLSearchParams(params);
par.append(name, id);
const href = `${url}?${par}`;
// 编码一下防止出现中文之类的
script.src = encodeURI(href);
document.body.appendChild(script);
script.addEventListener("error", () => {
clear();
return reject(
new Error(`Failed to create jsonp, request target address is:${url}`)
);
});
});
};
export default jsonp;
复制代码
这里为了方便演示使用了URLSearchParams
对象,它是浏览器的原生对象,用来构造、解析和处理 URL 的查询字符串,固然在生产中还须要polyfill
,若是不知足兼容性建议手写一个工具处理。git
参考:github.com/webmodules/…github
代码我已经放置到了仓库,欢迎来 Starweb