封装jsonp函数需要考虑的因素:

(涉及到传参->函数+请求参数,需要为封装的jsonp添加形参)

function jsonp(options) {}

1、script标签的创建

 var script = document.createElement('script');

2、请求地址中需要传递的参数、对参数进行拼接

var params = '';
// options中的data值为需要传递的请求参数,是要以key=value&key1=value1进行传递的,所以要进一步操作
for (var attr in options.data) {
    params += '&' + attr + '=' + options.data[attr];
}

3、避免同名函数的多次调用造成的函数覆盖-->采用随机命名法;需要将随机数小数点去掉

【注意】:下面提到的myJsonp是随意的,主要目的就是让函数名不相同,但是又不能只是数字

// 将生成的随机数中的点给去掉,再和函数名'myJsonp'拼接赋值给fnName
var fnName = 'myJsonp' + Math.random().toString().replace('.', '');

4、 将函数变为script可以调用的函数

      函数给到success意味着执行success()也就可以执行这个函数。

      but:script脚本是执行不到success的,因为它并非全局作用域函数

      so:要改为全局作用域,也就是window下,要以 [ ] 的格式,不能以 . 的格式

      对象确实存在的属性才可以使用.,而变量只能使用 [ ]

window[fnName] = options.success;

5、将函数名、参数拼接到请求地址中,再将请求地址赋值给script的src值

      将函数名同参数一起传递可以避免“手动控制服务器端和客户端的函数名一致”的麻烦

      这样依赖,服务器端一个req.query.callback就可以获取到动态的函数名

 script.src = options.url + '?callback=' + fnName + params;

6、将script追加到页面中

document.body.appendChild(script);

7、避免多次的调用而造成script的多次创建,当触发onload事件之后就给它从页面中删除

script.addEventListener('load', function() {
      document.body.removeChild(script);
})

调用封装好的jsonp函数

服务器3000客户端html代码:

<body>
    <button id="btn1">点我发送请求1</button>
     <script>
        var btn1 = document.getElementById('btn1');
        btn1.addEventListener('click', function() {
        jsonp({
                // 请求地址
                url: 'http://localhost:3001/better',
                // 请求参数
                data: {
                    firstname: 'xibing',
                    age: 18
                },
                success: function(data) {
                    alert('My name is:' + data.name);
                }
            })
        })
    </script>
</body>

服务器3001代码:(将函数名和(参数)进行拼接,然后通过send响应给客户端)

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

jsonp.get('/better', (req, res) => {
    const fnName = req.query.callback;
    // 对客户端发来的数据进行改造
    const name = req.query.firstname + '_G';

    // 注意格式:对象内的key对应的value需要以双引号包裹哦
    // const result = fnName + '({name:"xibing_G"})';
    const result = fnName + '({name:"' + name + '"})';
    res.send(result);
})


jsonp.listen(3001);
console.log('3001已监听');

(1)、客户端传送请求参数中有firstname:xibing

(2)、服务端通过req.query.firstname接收并进行改造,再放在函数中作为实参响应给客户端 

(3)、客户端执行响应函数(已存在服务端加入的实参)

(4)、最后:函数体中的弹窗弹出客户端的内容+服务端对客户端传入的参数改造后的数据。

(5)、其中:客户端获取到响应内容【函数fnName(.....)】后开始调用响应结果,

                        因为已经将success放到全局中,所以这里调用到success完全没问题。

原理就是:

        script会向服务器端发送请求之后去执行服务器端响应的内容

        客户端端传递函数,函数经由服务器端进行改造(例如:传递实参)

        客户端再将实参传递进去并调用这个函数(为了可以调用到,提前将函数放到全局下)

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐