jsonp封裝

本文介紹 jsonp 的一種封裝方式

jsonp 是一種跨域 ajax 技術

jsonp 請求步驟

  1. 建立 script 標籤,設置 src 屬性爲請求的路徑
var script = document.createElement('script');
script.setAttribute('src',url);
  1. 聲明全局變量 funcname, 通常是相似
window['funcname'] = function(data){
    console.log(data);
}

這種形式的函數ajax

  1. 監聽 script 的 load 事件,在 load 事件清理變量名污染和 script 標籤
script.onload = function(){
    delete window['funcname'];
    script.parentNode.removeChild(script);
}
  1. 服務器端以必定的格式返回數據,通常是這種形式
var data = {}
res.end(
    `funcname({
    data : ${JSON.stringfy(data)}
})`
);

如上述所示,jsonp 在使用過程當中須要建立標籤,聲明全局回調函數等繁瑣步驟。本文將 jsonp 的細節封裝在內部,對外暴露回調的接口。使用者無需考慮 dom 操做,更多考慮在業務層上。express

問題的分析與解決

  1. 全局變量污染:經過引入 uuid 方式解決,爲每一次 jsonp 請求的回調函數建立一個全球惟一的變量名
  2. 繁瑣的 dom 操做:將細節封裝在內部,在 jsonp 回調函數中進行數據傳遞和清理操做

uuid 生成器不詳細展開

var uuid = function() { 
    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''), uuid = new Array(36), rnd=0, r; 
    for (var i = 0; i < 36; i++) { 
      if (i==8 || i==13 ||  i==18 || i==23) { 
        uuid[i] = '-'; 
      } else if (i==14) { 
        uuid[i] = '4'; 
      } else { 
        if (rnd <= 0x02) rnd = 0x2000000 + (Math.random()*0x1000000)|0; 
        r = rnd & 0xf; 
        rnd = rnd >> 4; 
        uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]; 
      } 
    } 
    return uuid.join(''); 
};

dom 操做和 事件監聽

var script = document.createElement('script')
var callbackFunctionKey = (opts && opts.callback) || 'callback'

// 避免污染全局變量
var callbackFunctionName = 'jsonp-' + uuid();
script.setAttribute('src', url + '?' + callbackFunctionKey + '=' + callbackFunctionName)

window[callbackFunctionName] = function(data){
  callback(data);

  // clean
  delete window[callbackFunctionName];
  script.parentNode.removeChild(script);
}

jsonp 簡單封裝

function Jsonp(url,callback,opts){
    var uuid = function() { 
        var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''), uuid = new Array(36), rnd=0, r; 
        for (var i = 0; i < 36; i++) { 
          if (i==8 || i==13 ||  i==18 || i==23) { 
            uuid[i] = '-'; 
          } else if (i==14) { 
            uuid[i] = '4'; 
          } else { 
            if (rnd <= 0x02) rnd = 0x2000000 + (Math.random()*0x1000000)|0; 
            r = rnd & 0xf; 
            rnd = rnd >> 4; 
            uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]; 
          } 
        } 
        return uuid.join(''); 
      }; 
    var script = document.createElement('script')
    var callbackFunctionKey = (opts && opts.callback) || 'callback'

    // 避免污染全局變量
    var callbackFunctionName = 'jsonp-' + uuid();
    script.setAttribute('src', url + '?' + callbackFunctionKey + '=' + callbackFunctionName)

    window[callbackFunctionName] = function(data){
        callback(data);

        // clean
        delete window[callbackFunctionName];
        script.parentNode.removeChild(script);
    }
    document.body.appendChild(script)
}

後端返回數據格式

const express = require('express');
const app = express();

app.get('/', function(req, res){
    var funcname = req.query['callback'];
    res.end( `
        window['${funcname}']({
            data : 'data'
        })
    `);
    console.log('get');
})

app.listen(3000);

更進一步

  • opts 能夠支持其餘參數
  • url 拼接操做難以控制
相關文章
相關標籤/搜索