被低估的前端模块化
title: 被低估的前端模塊化 tags:
- 前端模塊化 categories: 前端 date: 2017-03-25 18:18:55
對于前端的緩存主要包括靜態資源的緩存
為避免出現類似問題參考?變態的靜態資源緩存與更新
在經歷了上傳前端資源文件等之后測試發現了一堆問題
發現每一個出現問題的均是彈出對話框畫面,由于均是出現函數未定義,初步判斷為js加載順序問題
因此對比了生產實現和開發實現,發現現象如下
同樣的文件在生產環境下表現如此
分別出現在chrome的網絡面板XHR標簽和JS標簽下
對于兩個版本的差異出現在js加載的域不一樣(生產的域為當前服務器而開發環境為CDN)
那么為啥出現不同的域出現不同的加載行為呢?
我們知道對于瀏覽器存在同源策略www.ruanyifeng.com/blog/2016/0…
那么得出結論ajax請求是無法直接跨域的,因此大部分開發者使用了jsonp的方式
對于jsonp實質上是通過script的方式來進行跨域的,順便說到我們cdn的請求。
cdn的加載在正常畫面上是OK的,因為由瀏覽器來串行執行對應的內容,此時沒有問題。
但是當使用對話框插件之后實質上使用remote是通過ajax請求到對應的html,其次加載對應的js
無說明均為jQuery1.9.1
if ( hasScripts ) {doc = scripts[ scripts.length - 1 ].ownerDocument;// Reenable scriptsjQuery.map( scripts, restoreScript );// Evaluate executable scripts on first document insertionfor ( i = 0; i < hasScripts; i++ ) {node = scripts[ i ];if ( rscriptType.test( node.type || "" ) &&!jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) {if ( node.src ) {// Hope ajax is available...jQuery.ajax({url: node.src,type: "GET",dataType: "script",async: false,global: false,"throws": true});} else {jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) );}}} 復制代碼此時話分兩頭,當執行ajax時首先判斷
// A cross-domain request is in order when we have a protocol:host:port mismatchif ( s.crossDomain == null ) {parts = rurl.exec( s.url.toLowerCase() );s.crossDomain = !!( parts &&( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) ));}// Handle cache's special case and globaljQuery.ajaxPrefilter( "script", function( s ) {if ( s.cache === undefined ) {s.cache = false;}if ( s.crossDomain ) {s.type = "GET";s.global = false;}});if ( !s.hasContent ) {// If data is available, append data to urlif ( s.data ) {cacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + s.data );// #9682: remove data so that it's not used in an eventual retrydelete s.data;}// Add anti-cache in url if neededif ( s.cache === false ) {s.url = rts.test( cacheURL ) ?// If there is already a '_' parameter, set its valuecacheURL.replace( rts, "$1_=" + ajax_nonce++ ) :// Otherwise add one to the endcacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_nonce++;}} 復制代碼由上述代碼可以看出ajax默認請求script都會放棄使用緩存,將會出現在網絡面板看見形如_=ajax_nonce這樣的的后綴使得無法使用緩存
關于jQuery加載transport為
// Bind script tag hack transportjQuery.ajaxTransport( "script", function(s) {// This transport only deals with cross domain requestsif ( s.crossDomain ) {var script,head = document.head || jQuery("head")[0] || document.documentElement;return {send: function( _, callback ) {script = document.createElement("script");script.async = true;if ( s.scriptCharset ) {script.charset = s.scriptCharset;}script.src = s.url;// Attach handlers for all browsersscript.onload = script.onreadystatechange = function( _, isAbort ) {if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {// Handle memory leak in IEscript.onload = script.onreadystatechange = null;// Remove the scriptif ( script.parentNode ) {script.parentNode.removeChild( script );}// Dereference the scriptscript = null;// Callback if not abortif ( !isAbort ) {callback( 200, "success" );}}};// Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending// Use native DOM manipulation to avoid our domManip AJAX trickeryhead.insertBefore( script, head.firstChild );},abort: function() {if ( script ) {script.onload( undefined, true );}}};}});jQuery.ajaxTransport(function( s ) {// Cross domain only allowed if supported through XMLHttpRequestif ( !s.crossDomain || jQuery.support.cors ) {var callback;return {send: function( headers, complete ) {// Get a new xhrvar handle, i, 復制代碼對于同域的js如上文會設置crossDomain為false,此時由于jQuery默認的async為false,因此可以直接按照順序加載
對于cdn,此時由于s.crossDomain為true,
/ Base inspection function for prefilters and transportsfunction inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {var inspected = {},seekingTransport = ( structure === transports );function inspect( dataType ) {var selected;inspected[ dataType ] = true;jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );if( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {options.dataTypes.unshift( dataTypeOrTransport );inspect( dataTypeOrTransport );return false;} else if ( seekingTransport ) {return !( selected = dataTypeOrTransport );}});return selected;}return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );}```?因此上端代碼將會返回對象scriptTransport,此對象將會直接執行?```javascrpthead.insertBefore( script, head.firstChild ); 復制代碼由于未采用前端模塊化依賴,導致加載的順序不定(文件大小,網絡狀況),因此出現一系列的函數未定義
因此需要在部署cdn前優先完成前端模塊化建設。
其它外國的倒霉蛋連接一枚Script File Exectuing After Inline Script With CDN or External Domain On HTML injection
總結
- 上一篇: JavaMail与Spring整合
- 下一篇: 第 25 章 OpenManage