/* 1. 每一個jsonp請求惟一,防止緩存,每一個請求存儲內容以下 { callback: function(){}, scriptNode: [domNode] timer: [定時器] } 2. src的參數須要編碼 3. 請求超時,拋出錯誤 4. 使用說明,使用方式相似JQuey的ajax方式,例: jsonp({ url:[string], data:[obj], callback:[function], fail: [function], timeout: [number] }) */ function jsonp(opts) { if (!opts || !opts.url) { return; } // 初始化參數 var options = { url: opts.url, data: opts.data ? opts.data : null, callback: opts.callback ? opts.callback : null, fail: opts.fail ? opts.fail : null, timeout: opts.timeout ? opts.timeout : 3000 } var helper = { joinURL: function(url, data) { if (!url || !data) { return; } for (var i in data) { if (data.hasOwnProperty(i)) { if (url.indexOf("?") >= 0) { url += "&"; } else { url += "?"; } url += i + "=" + data[i]; } } return url; }, encodeURL: function(url) { var param = url.split("?")[1]; var url = url.split("?")[0]; var params = param.split("&"); var parLen = params.length; for (var i = 0; i < parLen; i++) { var paItem = params[i].split("="); url += url.indexOf("?") >= 0 ? "&" : "?"; url += encodeURIComponent(paItem[0]) + "=" + encodeURIComponent(paItem[1]); } return url; }, }; // new Date().getTime()不夠精確,加上count計數,確保惟一,也能夠使用隨機函數,但我認爲這樣更簡單。 if (window["count"]) { window["count"]++; } else { window["count"] = 1; } // requestId 惟一jsonp請求 var requestId = "jsonp" + new Date().getTime() + window['count']; var head = document.getElementsByTagName("head")[0]; var script = null; window[requestId] = {}; // 請求值拼接到url if (options.data) { options.url = helper.joinURL(options.url, options.data); } //建立script結點 script = document.createElement("script"); if (options.url.indexOf("?") >= 0) { script.src = helper.encodeURL(options.url + "&callback=" + requestId + ".callback"); } else { script.src = helper.encodeURL(options.url + "?callback=" + requestId + ".callback"); } script.charset = "UTF-8"; head.appendChild(script); window[requestId]["scriptNode"] = script; //從新封裝回調函數,調用後應刪除script結點,刪除該請求信息。 window[requestId]['callback'] = function(data) { try { options.callback && options.callback(data); } catch (e) { console.log(e); } finally { head.removeChild(window[requestId]["scriptNode"]); clearTimeout(window[requestId]["timer"]); delete window[requestId]; } }; // 超時調用 window[requestId]["timer"] = setTimeout(function() { //拋出異常,並作異常處理 try { throw new Error("over time"); } catch (e) { if (options.fail) { options.fail(e.message); } } head.removeChild(window[requestId]["scriptNode"]); delete window[requestId]; }, options.timeout); }