摘要:前言最近因為工作的緣故,幾乎把市面上所有庫都下載了一遍,卻發現沒有百分百讓我滿意的,最后自己手動改寫了,才符合了要求,也因此有了這篇文章。在這一點上不得不說做的很好,的函數包含了對各種情況的處理,還偽造了一個狀態碼的返回。
前言
最近因為工作的緣故,幾乎把市面上所有Jsonp庫都下載了一遍,卻發現沒有百分百讓我滿意的,最后自己手動改寫了Jsonp,才符合了要求,也因此有了這篇文章。本文示例詳實,代碼簡單,想弄明白Jsonp, 這一篇文章就夠了。
什么是Jsonp因為AJAX收到瀏覽器同源策略的限制,導致在跨域上有心無力,經常需要后臺同學的幫助。而在瀏覽器中,所有帶有src的標簽都是不受同源策略限制的,如image, script。Jsonp上就是利用了script標簽的這個特點,來實現跨域的。
其中,Jsonp和AJAX的原理完全不同,只不過Jquery帶了個很不好的頭,把兩個東西封裝在一起了,所以經常讓新的同學混淆了。
Jsonp的原理:script src
AJAX的原理:xhr
舉一個最簡單的Jsonp的例子:
Jsonp簡單示例
http://www.qq.com/getJsonp?callback=jsonCallback這個鏈接返回的內容應該是
jsonpCallback({ msg: success })
這樣,相當于后臺調用了前臺提前寫好的callback函數,將要返回的數據當做callback函數的參數傳入,這樣前端就拿到后臺傳回來的數據了。
改寫Jsonp但是坦白來說,單純的拿到數據并不能讓我們滿意。一個合適的請求函數,必然包含對成功、失敗、超時的處理,就像我們上面寫的那個簡單示例,一旦出現異常,就不能讓我們滿意了。
在這一點上不得不說Jquery做的很好,Jquery的Jsonp函數包含了對各種情況的處理,還偽造了一個http狀態碼的返回。
Jsonp和AJAX不同,是拿不到狀態碼的,但是Jquery對于所有的錯誤都賦予了一個404的狀態碼,也是機智
對比其他的組件庫(axios-jsonp, axios-jsonp-pro, jsonp, fetch=jsonp-es6), 要不就是完全沒有對超時的處理,要不然就是把錯誤和超時混成一譚,更有甚者,有些都不能自定義callback函數的名字。這簡直太過分了。
那我為什么不選擇Jquery呢?因為太大了,webpack引入JQuery后瞬間大了80K, 而且多帶帶將Jsonp打包出來也有70K的樣子,而我的源碼只有20K,這是我不能接受的。
jsonp這個組件的問題是沒有對錯誤的處理,理解了Jsonp的原理,我們能很容易的添加上這塊的邏輯,以下是添加后的源碼:
/** * Module exports. */ module.exports = jsonp; /** * Callback index. */ var count = 0; /** * Noop function. */ function noop(){} /** * JSONP handler * * Options: * - param {String} qs parameter (`callback`) * - prefix {String} qs parameter (`__jp`) * - name {String} qs parameter (`prefix` + incr) * - timeout {Number} how long after a timeout error is emitted (`60000`) * * @param {String} url * @param {Object|Function} optional options / callback * @param {Function} optional callback */ function jsonp(url, opts, fn){ if ("function" == typeof opts) { fn = opts; opts = {}; } if (!opts) opts = {}; var prefix = opts.prefix || "__jp"; // use the callback name that was passed if one was provided. // otherwise generate a unique name by incrementing our counter. var id = opts.name || (prefix + (count++)); var param = opts.param || "callback"; var timeout = null != opts.timeout ? opts.timeout : 60000; var enc = encodeURIComponent; var target = document.getElementsByTagName("script")[0] || document.head; var script; var timer; if (timeout) { timer = setTimeout(function(){ cleanup(); if (fn) fn(new Error("Timeout")); }, timeout); } function cleanup(){ if (script.parentNode) script.parentNode.removeChild(script); window[id] = noop; if (timer) clearTimeout(timer); } function cancel(){ if (window[id]) { cleanup(); } } window[id] = function(data){ cleanup(); if (fn) fn(null, data); }; // add qs component url += (~url.indexOf("?") ? "&" : "?") + param + "=" + enc(id); url = url.replace("?&", "?"); // create script script = document.createElement("script"); script.src = url; // 添加對錯誤的處理 script.onerror = function (evt) { if (fn) fn(new Error("Error")); if (timer) clearTimeout(timer) } target.parentNode.insertBefore(script, target); return cancel; }
因為大部分是人家的代碼,我也就不班門弄斧了,有需要的可以直接npm install jsonp, 然后比對node_modules/jsonp/index.js進行修改;有需要對Jsonp有更詳細的處理的,也可以在我的基礎上繼續添加。
總結Jsonp的本質就是創建一個回調函數,然后在遠程服務上調用這個函數并且將JSON數據形式作為參數傳遞,完成回調。比起另外兩種后臺無感知的跨域方案:image src、fetch no-cor,Jsonp可以對錯誤和超時進行處理,也能對后臺返回的數據進行分析;而對于AJAX,Jsonp免去了后臺添加跨域頭的煩惱,后臺的改動較小,一次寫好,終生受用(跨域頭還要不斷維護白名單)。這三種方案都有各自的使用場景,要在不同的場景進行恰當的選用,以上。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/92627.html
摘要:還是老規矩,從易到難吧傳統的定時器,異步編程等。分配對象時,先是在空間中進行分配。內存泄漏內存泄漏是指程序中己動態分配的堆內存由于某種原因程序未釋放或無法釋放,造成系統內存的浪費,導致程序運行速度減慢甚至系統崩潰等嚴重后果。 showImg(https://segmentfault.com/img/bVbwkad?w=1286&h=876); 網上參差不棄的面試題,本文由淺入深,讓你在...
摘要:還是老規矩,從易到難吧傳統的定時器,異步編程等。分配對象時,先是在空間中進行分配。內存泄漏內存泄漏是指程序中己動態分配的堆內存由于某種原因程序未釋放或無法釋放,造成系統內存的浪費,導致程序運行速度減慢甚至系統崩潰等嚴重后果。 showImg(https://segmentfault.com/img/bVbwkad?w=1286&h=876); 網上參差不棄的面試題,本文由淺入深,讓你在...
摘要:在中是主流布局方式。它有三種狀態正數零與負數。來看下運行效果。這是為正數的情況,如果,控件的大小就會根據設置的與來固定顯示。如果發現生效的方式請務必告知。在中有主軸與副軸之分,主軸控制的排列方向,默認為。默認值為,繼承父容器的屬性。 今天我們來聊聊Flexbox,它是前端的一個布局方式。在React Native中是主流布局方式。如果你剛剛入門React Native,或者沒有多少前端...
摘要:在中是主流布局方式。它有三種狀態正數零與負數。來看下運行效果。這是為正數的情況,如果,控件的大小就會根據設置的與來固定顯示。如果發現生效的方式請務必告知。在中有主軸與副軸之分,主軸控制的排列方向,默認為。默認值為,繼承父容器的屬性。 今天我們來聊聊Flexbox,它是前端的一個布局方式。在React Native中是主流布局方式。如果你剛剛入門React Native,或者沒有多少前端...
摘要:值得一提的是由于采用動態創建子類的方式生成代理對象,所以不能對目標類中的方法進行代理。動態代理中生成的代理類是子類,調試的時候可以看到,打開源碼可看到實現了和也就實現方法。 前面講到了動態代理的底層原理,接下來我們來看一下aop的動態代理.Spring AOP使用了兩種代理機制:一種是基于JDK的動態代理,一種是基于CGLib的動態代理. ①JDK動態代理:使用JDK創建代理有一個限制...
閱讀 2959·2021-11-23 09:51
閱讀 3783·2021-11-22 15:29
閱讀 3241·2021-10-08 10:05
閱讀 1562·2021-09-22 15:20
閱讀 978·2019-08-30 15:56
閱讀 1076·2019-08-30 15:54
閱讀 738·2019-08-26 11:54
閱讀 2640·2019-08-26 11:32