json移除一个元素_面试中如何实现一个高质量的JSONP

d9c0b6806e3928a5dcd5c7ea2fde1176.png

最近面试中问到候选人 JSONP ,发现大多数候选人 JSONP 原理都可以回答正确,但是如果让写代码实现一个 JSONP 函数,有很多人都写不出来,或者是考虑不全面,写出来的代码没法使用。


接下来我们一起来看,如何实现一个高质量的 JSONP 。


首先先来说一下 JSONP 的原理:

JSONP 原理

全称 JSON with Padding,是解决跨域问题的一种方案。

由于同源策略的限制,浏览器只允许请求当前源(域名、协议、端口)的资源,而 HTML 的 script 元素是一个例外。利用 script 元素的这个开放策略,网页可以得到从其它来源动态产生的 JSON 资料,而这种使用模式就是所谓的 JSONP。具体的实现上有几个关键点:

1、服务端返回的数据不是 JSON,而是 JavaScript,也就是说 contentType 为 application/javascript ,内容格式为callbackFunction(JOSN)
2、callbackFunction 需要注册在 window 对象上,因为 script 加载后的执行作用域是window作用域。
3、需要考虑同时多个 JSONP 请求的情况,callbackFunction 挂在 window 上的属性名需要唯一。
4、请求结束需要移除本次请求产生的 script 标签和window上的回调函数。
5、最好支持 Promise 。

代码实现


函数定义:

function jsonp ({url, data, callback}) {
    
}

url 是请求地址,data(Object类型) 是请求参数,callback(Function类型) 是回调函数。

使用方法:

jsonp({
  url: 'url',
  data: {  
    key1: 'value1'  
  },  
  callback (data) {  
    // data 是服务端返回的数据  
  }  
})

常规实现

先写一个JSON转Query参数的Function

function objectToQuery(obj) {
    const arr = [];
    for ( var i in o) {
      arr.push(encodeURIComponent(i)+ '=' +encodeURIComponent(o[i]));
    }
    return arr.join('&');
}
function jsonp ({url, data, callback}) {
    const container = document.getElementsByTagName('head')[0];
    const fnName = `jsonp_${new Date().getTime()}`;
    const script = document.createElement('script');
    script.src = `${url}?${objectToQuery(data)}&callback=${fnName}`;
    script.type = 'text/javascript';
    container.appendChild(script);

    window[fnName] = function (res) {   
        callback && callback(res);
        // 很多候选人漏掉clean这块
        container.removeChild(script);
        delete window[fnName];
    }

    script.onerror = function() { // 异常处理,也是很多人漏掉的部分
        window[fnName] = function() {
        callback && callback(
          'something error hanppend!'
        )
        container.removeChild(script);
        delete window[fnName];
      }
    }
    
}

Promise实现

在常规实现的基础上改造。

function jsonp ({url, data, callback}) {
    const container = document.getElementsByTagName('head')[0];
    const fnName = `jsonp_${new Date().getTime()}`;
    const script = document.createElement('script');
    script.src = `${url}?${objectToQuery(data)}&callback=${fnName}`;
    script.type = 'text/javascript';
    container.appendChild(script);
    
    return new Promise((resolve, reject) => {
    
        window[fnName] = function (res) {   
            // 很多候选人漏掉clean这块
            container.removeChild(script);
            delete window[fnName];
            resolve(res);
        }
    
        script.onerror = function() { // 异常处理,也是很多人漏掉的部分
            container.removeChild(script);
            delete window[fnName];
            reject('something error hanppend!');
          }
        }
  })
    
}

希望大家都能找到一个好工作!

需要内推的可以加我微信:

https://u.wechat.com/EHv139tCcQo7uycdQ8hVNHk (二维码自动识别)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值