如何在本机javascript Promise中包装jsonP回调?

时间:2015-03-12 21:36:53

标签: javascript ajax jsonp es6-promise

我正在使用原生Promise将一堆XmlHttpRequests合并到一个结果中,我认为我已将其运行,请参阅http://jsfiddle.net/pjs06hdo/ (随机调用flickr api,查看控制台实际按顺序进行的操作)

可能会有更短的实现,但使用此代码我可以理解正在发生的事情。

然后出现了愚蠢的JSONP :-(因为事实证明实际的目标站点不允许跨站点请求,我必须使用提供的jsonP端点(再次使用flickr模拟)并且在这里我' m卡住:这个愚蠢的全球回调不符合我对Promise

的基本理解

我认为解决方案与How do I convert an existing callback API to promises?中的解释有关。

我试图实现这个但它只能部分工作:http://jsfiddle.net/b33bj9k1/没有实际输出,只有控制台消息,抱歉。但是在那里你可以看到有三个调用来创建promise,但是resolve()jsonFlickrApiAsync()只被调用一次。

使用Promise处理jsonP回调的正确方法是什么,所以我可以使用Promise.all()处理结果,就像上面的XmlHttpRequest版本一样?

请不要jQuery - 我想了解最新情况

1 个答案:

答案 0 :(得分:3)

这不是承诺的问题,这是JSONP的问题。由于它使用全局回调,因此您需要为每个请求使用不同的回调 - 具有不同的名称。对于Flickr,这意味着您必须使用their jsoncallback url parameter。参数名称可能因实际终点而异。


然而,你对承诺的使用确实很奇怪。通常,您会为每个请求使用一个承诺来表示该请求的结果。您有意只创建一个全局承诺,但这无效。

function loadJSONP(url, parameter="callback") {
    var prop = "loadJSONP.back" + loadJSONP.counter++;
    var script = document.createElement("script");
    function withCleanUp(r) {
        return (x) => {
            loadJSONP[prop] = null;
            document.head.removeChild(script);
            r(x);
        }
    }
    return new Promise((resolve, reject) => {
        loadJSONP[prop] = withCleanUp(resolve);
        script.onerror = withCleanUp(reject);
        // setTimeout(script.onerror, 5000); might be advisable

        script.src = url+"&"+parameter+"="+prop;
        document.head.appendChild(scr);
    });
}
loadJSONP.counter = 0;