2020年7月以來,持續對 UfqiLong 有福常在 進行升級改進。
改進過程中遇到之前不曾見的問題,在使用 GTAjax進行非同步遞交 有福常在UfqiLog 的文章內容時,有隨機性地出現遞交失敗。進一步的跟蹤發現,儅點選遞交後,GTAjax接管了表單遞交動作並觸發了進度顯示並進行讀秒操作。
但是,詭異的是,GTAjax在後臺並未真的將遞交傳送給伺服器端後臺。於是我們決定對 GTAjax開啟 debug 模式,進行深入分析,為何之前不曾有這樣的問題,為何問題會是隨機性出現,而又為何,儅第一次遞交失敗後,第二次原樣操作,卻能成功?
帶著這些問題,我們準備深入分析一下。開啟 GTAjax的debug模式相對簡單,在 執行時引數裡:
var myGTAjax = new GTAjax();
myGTAjax.set(‘isdebug’, true);
這樣即可開啟 GTAjax 的過程資料輸出,從而觀測到整個通訊過程。通過分析debug日誌,問題很快鎖定到 postForm.submit() 這個節點上。
也即,在使用 ForceFrame 模式進行表單遞交時,依賴 JavaScript的 HTMLFormElement.submit() 這個方法進行最終的資料遞交。
這個是 W3C、HTML DOM和 JavaScript等標準組織封裝好的方法,無法進一步地往下拆解。問題就轉化為為何 submit() 遞交失敗呢?通過進一步地分析,我們發現在 GTAjax 接管真正的 HTML Form表單時,通常會通過 _DFM_F 方法將 onsubmit 返回一個 false,從而阻止正常的遞交,然後GTAjax 再開展一系列的準備動作之後,再遞交 postForm.submit() 進行遞交。
詭異的地方在於,Google Chrome、MS Edge等瀏覽器,之前即便對HTML Form設定了 _DFM_F, 呼叫 postForm.submit() 時並不會受影響,而且儅 GTAjax 通過 _RGT 方法進行初始化設定之後再次呼叫 _DFM_F ,然後再次 postForm.submit() 時,卻是可以通行過去,如預期地進行與伺服器端的通訊。
我們推測,可能是近期的Google Chrome和MS Edge瀏覽器的升級,增加了對HTML Form遞交前的JavaScript等狀態檢查,所以如果發現某個Form的onsubmit 繫結了 return false的動作,就自動終止當前的操作;相反,則繼續如常。
定位到問題,並經過粗略的原因分析之後,解決問題的辦法也就隨之而來。如果當前被執行的HTML Form被設定了 onsubmit 的檢查,則需要對已經設定的 onsubmit 進行重寫,使之能夠覆蓋之前的設定,尤其是之前 return false 的設定,以使得後續的Form遞交操作能夠順利進行。 改進主要集中在 _SUB 這個內部呼叫的子函式上。
在執行postForm.submit() 之前,對當前 postForm的onsubmit 進行檢查。
//postForm.submit(); // maybe fail due to this.\_DFM\_F . 10:42 2020-07-04
if(postForm.onsubmit == null){
postForm.submit();
GTAj.\_DBG(GTAj.vA\[‘ib’\], ‘this.\_SUB’, ‘Sync form: \[‘+postForm.name+’\] is being submitted.’);
}
else{
GTAj.currentPostFormId = postForm.name!=” ? postForm.name : postForm.id;
postForm.onsubmit = (function(){
var myTimerId = window.setTimeout(function(formId){
document.getElementById(GTAj.currentPostFormId).submit();
GTAj.\_DBG(GTAj.vA\[‘ib’\], ‘this.\_SUB’, ‘Async form:\[‘+GTAj.currentPostFormId+’\] is being submitted.’);
}, 10); //- 0.01 sec
return true;
})();
}
如果當前被執行的 postForm的onsubmit 沒有被設定過,則繼續使用之前的邏輯,直接執行 postForm.submit();
如果當前被執行的 postForm的onsubmit已經被設定過,則需要重寫onsubmit的繫結與賦值操作。經過多次實驗,我採取了JavaScript anonymous function的方式,重新對當前postForm的onsubmit進行賦值操作。初始我們將一個匿名函式賦值給當前的 postForm, 形如:
postForm.onsubmit = function(){ return true; }
在我們的實測過程中,這一匿名函式,在不同應用場景和不同的瀏覽器中,仍有一定的隨機性出現匿名函式不被執行的情況。為保全起見,我們進一步地改進這個匿名函式,不但定義了匿名函式同時隨後執行這個你們函式,將返回值賦給 postForm.onsubmit .
在匿名函式體外,我們還通過全域性變數 GTAj,將當前被執行的postForm的相關資訊帶入匿名函式內;在匿名函式體內,我們設定了一個隨後立即執行的新的匿名函式,這第二個內嵌的匿名函式將完成這個表單的真實遞交動作。執行的時序變成: …. 1)定義一個匿名函式A—- 2)在匿名函式A內定義另一個非同步的匿名函式B—- 3)執行這個匿名函式A —- 4)將匿名函式A的返回值true賦值給 postForm.onsubmit —- 5)時間觸發執行匿名函式B —– 6)實際執行postForm.submit() 操作 —– 7)監測伺服器返回值進度….
改進後,分別在 Google Chrome,MS Edge 和 Mozilla Firefox 多個瀏覽器的不同應用場景下實測,均取得預期效果,不再發生或者隨機性發生,遞交Form未被執行的情況,故障問題得到順利解決。完整程式原始碼可以在 GTAjax 主頁( https://ufqi.com/dev/gtajax/ )和 GitHub上查詢(wadelau/GTAjax)。
這可能是軟體更新史上間隔最長的一次更新,GTAjax的官網主頁記錄記錄的上次更新時間為 2011-07, 距今已經九年過去了。著實令整個軟體作者也感到時光飛逝,一方面感慨時間過得太快,同時也對 GTAjax 歷時十多年,還能夠堅強、頑強地服務於業務系統的旺盛生命力感到一陣驚喜。
這不就是那種“Best as Air(好到無形)”極好的案例嗎? 幾乎每個工作日開啟的基於 gMIS 吉密斯系統,其中都有 GTAjax 工作的身影,而他總是能夠不負囑託,完成每一次基於 GTAjax 的HTTP請求。
實際上,2011年以來,GTAjax 也做過小幅的升級改進和Bug修復,根據軟體原始碼中的更新標記,至少有如下幾次。
* GTAjax.js
* @abstract: General-Targeted Ajax
* @author: wadelau@hotmail.com,wadelau@gmail.com
* @since: 2006-2-17 14:04
* @code: 5.7 // a.bc , funcs added b+, errs updated c+
* @NOTICE: DO NOT USE THIS COMMERICALLY WITHOUT AUTHOR’S PAPER AUTHORIZATION
* @update: Tue Feb 1 20:47:03 GMT 2011
* Wed Jan 26 17:31:33 GMT 2011
* Wed Jul 20 08:08:09 BST 2011
* Fri Mar 16 16:36:52 CST 2012
* 12:15 Friday, February 20, 2015
* Sun Jan 24 12:56:43 CST 2016
* Fri May 25 08:51:23 CST 2018, code format refine and cA.sort bugfix
* Wed Oct 31 21:57:26 CST 2018, +form Name validate
* 11:06 Friday, August 16, 2019, imprvs with form validate
* 11:55 2020-07-04, bugfix for submit fail with forceFrame.
GTAjax 初創於 2006年2月,距今已經有 15年的歷史了。對於日新月異的軟體及網際網路行業來説,這差不多是古董級的軟體了。然而,基於開放標準和成熟技術棧,15年後,GTAjax依然穩定執行和應用在各種Web軟體中,這不能不説是相當成功的案例。
可以設想和對比的是,在應用層軟體,有有多少能使用15年之久?不要說15年,基於私有類庫和標準而開發的軟體,可能5年、10年之後已經難以覓得蹤跡,GTAjax 伴隨 gMIS 吉密斯 等軟體能夠一直執行到現在,並繼續執行到下一個5年,10年,是一件值得慶賀的事情。
軟體的生命力或者生存週期有多久?需要多久? 摩爾定律說硬體計算速度每18個月翻倍,軟體是否也只能用18個月要改版、升級換掉,甚至是完全推導重建?
實際上,GTAjax 生存的越久,越有可能遇到“趕不上趟”的情況,畢竟技術的發展與進步,日新月異,每隔3-5年幾乎就是天翻地覆的改變。GTAjax能夠堅持其可用、好用、能用達15年之久,應該說算是某種“成功”。
幾乎同時期的很多軟體都已經銷聲匿跡了。也可以設想,如果不是使用的開放的HTML、CSS和JavaScript等標準,而是使用某一家公司的某項私有技術,其情況可能就完全無法預料,更誑論與時俱進、歷久彌新了。縱向地時間跨度看,要保護和珍視一個軟體,盡可能延遲其生命週期,保持旺盛生命力,唯一可取的方式就是使用開放的技術與標準,構建面嚮未來的軟體。
從這一方面來説,基於WEB的應用軟體已經完勝了基於某個公司或者平臺的“本地應用”。10年前,差不多是WEB軟體真大行其道的時候,以美國Apple公司的Appstore反其道而用之,強推基於其自有的平臺軟體(App),構築強大的軟體壁壘,同時引導、脅迫無數軟體開發者不斷的為其開發軟體(App),短則數月,長則數十月,App的快速更迭,也意味著大量的新寫成的程式碼,像曇花一現一般消失了。
當然,也有及其少數的本地應用App頑強地頻繁地更新升級穿越了10年以上的歲月時空,如遊戲魔獸世界WoW,即時通訊軟體騰訊QQ等。這其中也包括,Web軟體賴以執行的網路瀏覽器,如MS IE,Mozilla Firefox,Google Chrome,Apple Safari,Opera等。
在人民網工作期間,儅其實我們用的基於WEB的內部辦公系統(OA)相當有些年份(5-6年?),當時覺得,為何不升級採用新技術? 甚至是再一個5-6年之後(10多年前),這個OA系統依然在執行中。現在想來,這是一筆極大的財富,因為軟體的本身的技術棧是公開的標準,沒有很快地被業界全部拋棄,所以企事業單位的投資,得以延用至今繼續發揮作用。
當然,也不是說公開、開發的技術標準就止步不前,相反,公開、開放、開源的技術也在不斷的改進升級,只是由於影響巨大,各方需要多輪磋商,考慮各種因素,相對於一家公司的一項技術,其進度必然是緩慢的,當然也是理性而鑒定的。
比如 GTAjax 在開發計劃中,就規劃了 GTAjax-6.x 版本,主要考慮外部因素如下:
* 12:15 Friday, February 20, 2015
* 6.x Bears
HTML 5
ECMAScript 5, 6
HTTP/2 and Event-driven,
highly-cached,
code style of high-performance and readability
* in mind
尤其是其中的 HTML5,JavaScript 6 和 HTTP2 這些是在業界公開討論多年的技術標準,日益成熟,在新應用部署時會加快採用。相信在不久的將來,GTAjax-6.x 就緒時,能夠充分利用這些新技術特徵,在相容之前的前提下,繼續為網際網路社群做出新的貢獻,下一個 15年,30年,50年。
與之相關 GTAjax更新Blog有:1)gMIS吉密斯更新Workflow工作流、FileMgr檔案櫃及GTAjax等模組( https://ufqi.com/blog/gmis-workflow-filemgr-gtajax/ ),2)-gMIS, -GWA2, -GTAjax 一併更新 ( https://ufqi.com/blog/gmis-gwa2-gtajax-update/ )。
世界仍不平靜,新冠肺炎疫情仍在傳播,願軟體開發者多開發些生命週期更長的軟體,為世界和平貢獻智慧和力量,不要讓軟體成為快消品, 而是要讓軟體成為耐用品、藝術品。