如何在原生 JavaScript Promise 中包装 jsonP 回调

How to wrap jsonP callback in native javascript Promise?

本文关键字:包装 jsonP 回调 Promise JavaScript 原生      更新时间:2023-09-26

我正在使用本机 Promise,将一堆 XmlHttpRequests 组合成一个结果,我想我让它工作了,请参阅 http://jsfiddle.net/pjs06hdo/(随机调用Flickr API,请参阅控制台以了解实际发生的顺序)

可能会有更短的实现,但通过这段代码,我可以理解发生了什么。

但是接下来出现了愚蠢的JSONP :-(事实证明,实际的目标站点不允许跨站点请求,我必须使用提供的jsonP端点(再次使用flickr模拟)在这里我被困住了:那个愚蠢的全局回调不符合我对Promise的基本理解

我认为解决方案与如何将现有回调 API 转换为承诺中的解释有关?。

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

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

请不要使用jQuery - 我想了解到底发生了什么

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

<小时 />

然而,你对承诺的使用确实很奇怪。通常,您会为每个请求使用一个承诺来表示该请求的结果。你有意只创造了一个全球承诺,这是行不通的。

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(script);
    });
}
loadJSONP.counter = 0;