用TypeScript造一個jsonp的輪子

先說一下爲何要造這個輪子javascript

  1. axios 不支持 jsonp;
  2. 而 jQuery 雖然封裝的有,但爲了一個 jsonp 增大致積確定不可取;
  3. github 上封裝的回調形式居多,不支持 Promise,而支持 Promise 的又不支持併發請求(只簡單看了幾頁,別打臉);

因此決定造一個支持上面功能的輪子html

jsonp

簡單說一下存在的歷史,瀏覽器存在同源政策,即域名+端口+協議必須一致,不少時候咱們須要跨域訪問,因此 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

相關文章
相關標籤/搜索