LoginSignup
17
15

More than 5 years have passed since last update.

【Promise】JSONPの読み込みをThenableにする

Last updated at Posted at 2015-08-29

関数定義

JavaScript初心者なので改善点あればマサカリください。

jsonp_loader.js
function loadJSONP(url, params, timeout, callbackParamName) {
    params = params || {};
    timeout = timeout || 0;
    callbackParamName = callbackParamName || 'callback';
    var callbackName = 'jsonpCallback' + Math.random().toString(16).slice(2);
    params[callbackParamName] = callbackName;
    url += '?' + Object.keys(params).map(function (key) {
        return encodeURIComponent(key) + '=' + encodeURIComponent(params[key]);
    }).join('&');
    var script = document.createElement('script');
    script.src = url;
    document.body.appendChild(script);
    return new Promise(function (resolve, reject) {
        window[callbackName] = resolve;
        script.addEventListener('error', reject);
        if (timeout > 0) {
            setTimeout(reject, timeout);
        }
    }).then(function (response) {
        delete window[callbackName];
        document.body.removeChild(script);
        return Promise.resolve(response);
    }, function (e) {
        var msg = e ? 'Execution Failed' : 'Request Timeout';
        delete window[callbackName];
        document.body.removeChild(script);
        return Promise.reject('JSONP ' + msg + ': ' + url);
    });
}

最初エラーハンドリングの方法に悩んでいたのですが、onerror属性で何とかなりました。@gaogao_9さん助言ありがとうございました。

@chitokuさんによりよい方法を教えていただいたので採用しました。

@Raggさんにdeleteの提案をいただきました。

ついでにタイムアウトでエラーにする機能も付けました。

@think49さんにObject.keysの提案をいただきました。

使用例

面倒なのでHTML5の最省略形で書いてます。

index.html
<!DOCTYPE html>
<title>example</title>
<script src="jsonp_loader.js"></script>
<script>
    // はてなブックマークの総数を並列に取得してきて
    // 全部終わったらコンソールに表示するだけのコード
    window.onload = function () {
        var hatebuUrl = 'http://api.b.st-hatena.com/entry.counts';
        var list = [
            'http://www.google.com/',
            'http://yahoo.co.jp/',
            'http://twitter.com/',
            'http://qiita.com/'
        ];
        Promise.all(list.map(function (url) {
            return loadJSONP(hatebuUrl, {url: url});
        })).then(function (results) {
            console.log(results); // レスポンスの配列になってます
        }, function (message) {
            console.error(message); // 最初の1件のエラーのみ取り扱われます
        });
    };
</script>

実際には、はてブAPIは50件まで一気にまとめてリクエスト出来るようなので、出来る限りそれに従った実装を採り、サーバに負荷をかけないようにしましょう。

17
15
14

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
15