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 拼接操做难以控制
相关文章
相关标签/搜索