jsonp模块实现跨域及其源码分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/momDIY/article/details/83869828

一、简介

jsonp是npm模块中很常用的跨域依赖模块,语法简洁,上手无难度。

二、基本使用

1.安装依赖

npm i jsonp

2.引入模块

import jsonp from 'jsonp'

3.使用

jsonp(url,option,fn);
  • 参数一 请求的url
  • 参数二 配置对象
    • param 防缓值存字段名
    • prefix 防缓存字段值前缀
    • name 防缓存字段值完整名称
    • timeout 请求超时时间
  • 参数三 回调函数

该模块,使用非常简单,想了解防缓存原理或jsonp实现原理可以看下下面的源码分析。

三、源码分析

源码中使用到了debug模块进行调试输出,与jsonp本身无关已经剔除,以下代码不需要依赖任何模块

// 导出为jsonp模块
module.exports = jsonp;


// 用于防止get请求缓存的计数器字段
var count = 0;

// 占位空函数
function noop(){}

/**
 * JSONP handler
 *
 * Options:
 *  - param {String} qs parameter (`callback`)
 *  - prefix {String} qs parameter (`__jp`)
 *  - name {String} qs parameter (`prefix` + incr)
 *  - timeout {Number} how long after a timeout error is emitted (`60000`)
 *
 * @param {String} url
 * @param {Object|Function} optional options / callback
 * @param {Function} optional callback
 */

function jsonp(url, opts, fn){
  //设置第二个参数为可选
  if ('function' == typeof opts) {
    fn = opts;
    opts = {};
  }
  if (!opts) opts = {};

  // 设置存放防缓存字段的值的前缀
  // 举个栗子 url中默认的请求信息为 &callbacknice=__jp2
  var prefix = opts.prefix || '__jp';

  //  设置存放防缓存字段的完整值名称
  var id = opts.name || (prefix + (count++));
    // 设置存放防缓存字段的键名
  var param = opts.param || 'callback';
  var timeout = null != opts.timeout ? opts.timeout : 60000; //设置超时时间,默认60秒
  var enc = encodeURIComponent; // encodeURIComponent函数可把字符串作为 URI 组件进行编码 在这里是使用enc简化较长的函数名
  var target = document.getElementsByTagName('script')[0] || document.head; //存放用于跨域的script标签位置的节点
  var script;
  var timer;

  //超时时间到时执行,用于清除计数器、移除节点。当为请求成功抛出异常
  if (timeout) {
    timer = setTimeout(function(){
      cleanup();
      if (fn) fn(new Error('Timeout'));
    }, timeout);
  }

  // 移除节点、全局函数、清除计时器
  function cleanup(){
    if (script.parentNode) script.parentNode.removeChild(script);
    window[id] = noop;
    if (timer) clearTimeout(timer);
  }

  // 取消请求
  function cancel(){
    if (window[id]) {
      cleanup();
    }
  }
  //防止重复的释放缓存的函数
  window[id] = function(data){
    cleanup();
    if (fn) fn(null, data);
  };

  // 将请求的参数拼接成jsonp支持的格式,并把字符串进行url组件编码
  url += (~url.indexOf('?') ? '&' : '?') + param + '=' + enc(id);
  url = url.replace('?&', '?');

  // 创建script标签,设置script标签的src属性进行跨域,最后将script标签插入页面
  script = document.createElement('script');
  script.src = url;
  target.parentNode.insertBefore(script, target);

  return cancel;
}

该模块的底层实现还是使用script标签进行跨域请求,其中最主要的操作就是防止请求被缓存。以上代码已加入中文注释,希望您仔细阅读一遍上边的源码,祝您有所收获

END

猜你喜欢

转载自blog.csdn.net/momDIY/article/details/83869828
今日推荐