我的普通 JSONP 的回调范围是什么

What is the scope of the callback on my vanilla JSONP

一点背景故事,我正在使用 Twitch(游戏流媒体服务)api 从网站上的频道中提取关注者列表。为了绕过 CORS 规则,我使用了 JSONP。就个人而言,我更喜欢使用 vanilla javascript 而不是库,所以我从 https://cameronspear.com/blog/exactly-what-is-jsonp/ 上的优秀文章中学习了如何使用它。

下面是我的简化 javascript(实际代码可能不是非常必要,但可能有助于澄清我的问题):

//Function to pull JSONP

function pullJSONP(url) {

    var JSONPInstance = document.createElement('script');
    JSONPInstance.src = url;

    JSONPInstance.onload = function () {
        this.remove();
    };

    var head = document.getElementsByTagName('head')[0];
    head.insertBefore(JSONPInstance, null);
} 


//End function to pull JSONP


function storeCurrentFollows(offset) //Function to wrap entire operation
{


    function pullStartSessionFollows(JSONdata) //Callback from JSONP down below
    { 


        function pushNameElements(followEntry) //Function to add names into array
        {

            allSessionFollows.push(followEntry.user.name);

        }

        JSONdata.follows.forEach(pushNameElements); //Iterate through followers

        storeCurrentFollows(offset+100); //Rerun operation, incrementing offset by 100

    }; 

    if(offset > 300){ return }
    else
    {
        //running JSONP function from above, passing in url and setting a callback
        pullJSONP('https://api.twitch.tv/kraken/channels/' + channelName + '/follows?direction=desc&limit=100&offset=' + offset + '&callback=pullStartSessionFollows');

    }


}


storeCurrentFollows(0);

所以我的问题是,每当我 运行 以这个顺序对项目进行此操作时,它 returns 控制台中的错误 > Uncaught ReferenceError: pullStartSessionFollows is not defined。除非我将 pullStartSessionFollows 函数向上移动到全局范围内,否则它无法正常工作。我不明白的是为什么它认为它是未定义的,即使它是在我 运行 pullJSONP() 函数之前实例化的。我不想移动它,因为那样我就必须将我的偏移量传递给两个不同的函数以及其他一些问题。任何帮助或见解将不胜感激。提前致谢!

作为 JSONP 回调调用的函数必须是全局的(或全局对象的 属性)。作为响应主体从 JSONP 服务返回的回调表达式在全局上下文中进行评估。服务器正在返回类似于

的内容
pullStartSessionFollows({ ... });

你的函数是在另一个函数中定义的,所以它不是全局的。

It doesn't work properly unless I move the pullStartSessionFollows function up into the global scope.

正确,JSONP 回调必须是全局函数。它是 JSONP 工作方式的固有特性。

What I don't understand is why it thinks it is undefined even though it is instantiated just before I run the pullJSONP() function.

因为这会在您执行此操作的函数内创建函数 (storeCurrentFollows),而不是作为全局函数。但是 JSONP 的工作方式要求函数是全局的。

您可以让 pullStartSessionFollows 函数仅在您有待处理的 JSONP 调用时存在,方法是将其声明为全局变量:

var pullStartSessionFollows;

...然后分配给 storeCurrentFollows:

pullStartSessionFollows = function() { /* ... */ };

您也可以在回调完成其工作后将其删除:

pullStartSessionFollows = undefined;

为什么回调函数必须是全局的?因为 JSONP 的工作方式是通过向页面添加一个脚本元素,就好像您在 HTML:

<script src="http://example.com/get?callback=pullStartSessionFollows"></script>

...然后响应如下所示:

pullStartSessionFollows({/*...JSON here...*/})

这要求它是一个全局函数。

jsonp 回调必须在全局 javascript 范围内,因为在请求完成时,无法确定回调函数的原始范围,这就是为什么它将在全局范围内执行几乎可以从任何范围访问的范围。