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);
}

这种形式的函数

  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 操作,更多考虑在业务层上。

问题的分析与解决

  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 拼接操作难以控制

转载于:https://www.cnblogs.com/Salaku/p/8298771.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值