摘要:只要保證在開發(fā)中沒有對(duì)共享對(duì)象的寫入操作,那么發(fā)布到線上時(shí)肯定也沒有寫入操作,這時(shí)候這個(gè)保護(hù)方法就是多余的。
什么是共享對(duì)象
被多次使用到的同一個(gè)對(duì)象即為共享對(duì)象
比如我們用標(biāo)準(zhǔn)的es模塊來寫一個(gè)導(dǎo)出單位轉(zhuǎn)換的模塊
//converter module export default { cmToIn(){ //convert logic } }
當(dāng)我們?cè)谄渌K中使用該模塊時(shí),converter即是共享對(duì)象,內(nèi)存中只有一份,不管它被import了多少次。
同理,上面展示的是通用方法的對(duì)象集合,在前端項(xiàng)目里,我們也會(huì)把一些所謂寫死的數(shù)據(jù)集中封裝在某個(gè)模塊里,方便后期的修改,比如我們實(shí)現(xiàn)一個(gè)constant常量模塊,我們把一些項(xiàng)目中使用的,后期可能會(huì)修改的數(shù)據(jù)放進(jìn)去
//constant export default { dateFormatter:"YYYY-MM-DD", reports:{ productId:"123", productName:"456" } }
這里僅示意一下
為什么要保護(hù)共享對(duì)象防止共享的對(duì)象被意外修改導(dǎo)致線上故障
原則上這些通用的模塊,我們不會(huì),也不會(huì)有意的在我們業(yè)務(wù)代碼中去修改里面的數(shù)據(jù),尤其像常量這樣的模塊,如果要修改的話,我們肯定修改常量這個(gè)模塊。
但是,凡事總有意外,比如說我們有這樣一個(gè)場(chǎng)景:根據(jù)后端返回的用信息,以及前端寫死的一些常量,來判斷某個(gè)用戶能不能展示某個(gè)報(bào)表,我們期望的代碼可能是這樣的
import Constant from "./constant";//引入我們前面定義的constant模塊 //...其它略 export default View.extend({ render(){ //...其它邏輯略 if(Constant.reports.productId==user.reportProductId){ //.... } } });
注意上述代碼中的if語句,如果錯(cuò)寫成:if(Constant.reports.productId=user.reportProductId),兩個(gè)等號(hào)的比較寫成了一個(gè)等號(hào)的賦值。
如果自測(cè)的時(shí)候,用戶接口里user.reportProductId返回的正好也是123,那么先賦值,再做if判斷,成立,做為開發(fā)者會(huì)錯(cuò)誤的以為這里的邏輯沒問題。當(dāng)然,正常情況下也要測(cè)試下用戶接口里user.reportProductId返回不是123的情況,這時(shí)候或許就能發(fā)現(xiàn)問題。
如果上述問題沒有測(cè)試出來,陰差陽錯(cuò)的上線之后,這個(gè)問題對(duì)于大型單頁應(yīng)用是致命的,如果某個(gè)用戶的reportProductId是456,訪問了寫錯(cuò)的頁面后,因?yàn)楸灰馔獾男薷牧?b>constant中的reports.productId,會(huì)導(dǎo)致后續(xù)其它模塊在讀取時(shí)不再是最初的123而出問題
如何保護(hù)共享對(duì)象 constconst關(guān)鍵字聲明的僅防止變量被重新賦值,無法防止對(duì)象修改Object.freeze
可以防止被修改,但是如果對(duì)象嵌套時(shí),被嵌套的對(duì)象依然可以被修改,需要開發(fā)者對(duì)要freeze的對(duì)象遞歸遍歷進(jìn)行freeze。最重要的一點(diǎn)是,當(dāng)我修改一個(gè)freeze對(duì)象時(shí),雖然修改不成功,但也沒有任務(wù)失敗的提示,在前述場(chǎng)景中,我們還是希望開發(fā)者在修改一個(gè)不允許的被修改的對(duì)象時(shí)能及時(shí)給出相應(yīng)的提示。Proxy
es6新增的代理操作對(duì)象的方法
Proxy相關(guān)的文章非常多,這里就不再詳細(xì)說,我們借助Proxy來實(shí)現(xiàn)一個(gè)Safeguard方法來保護(hù)我們的共享對(duì)象
const Safeguard = o => { let build = o => { let entity = new Proxy(o, { set() { throw new Error("readonly"); }, get(target, property) { let out = target[property]; if (target.hasOwnProperty(property) && (Array.isArray(out) || Object.prototype.toString.call(out) == "[object Object]")) { return build(out); } return out; } }); return entity; }; return build(o); }
這里簡化了代碼,你可以根據(jù)自己的需要去調(diào)整相應(yīng)的實(shí)現(xiàn)邏輯
使用
const user=Safeguard({ name:"行列", address:{ city:"hz" } });
這個(gè)user對(duì)象只能讀,不能寫,當(dāng)開發(fā)者嘗試寫入新數(shù)據(jù)時(shí),會(huì)拋出錯(cuò)誤提示開發(fā)者
使用場(chǎng)景 地址欄解析對(duì)象在單頁應(yīng)用中,我們需要把地址欄中的字符串地址解析成對(duì)象,方便我們使用。
比如/path/name?a=b&c=d,我們可能解析成這樣的對(duì)象
{ path:"/path/name", params:{ a:"b", c:"d" } }
如果你統(tǒng)計(jì)過你的單頁應(yīng)用,會(huì)發(fā)現(xiàn)固定的用戶總是只訪問某些頁面,我們可以在用戶訪問某個(gè)頁面時(shí),臨時(shí)的把地址欄中的這個(gè)地址字符串解析一遍,也可以把解析結(jié)果存起來,當(dāng)用戶再訪問這個(gè)頁面時(shí),不需要解析,把存起來的結(jié)果拿出來使用即可
關(guān)于這一塊我曾經(jīng)寫過Magix.Cache,詳細(xì)的來說明該如何智能的緩存哪些需要的信息
對(duì)于緩存后的地址欄信息對(duì)象,它就是一個(gè)共享對(duì)象,要確保它不能被開發(fā)者寫入新的值,就可以使用前面我們定義的Safeguard方法來進(jìn)行保護(hù)
緩存的接口數(shù)據(jù)在單頁應(yīng)用開發(fā)中,有些數(shù)據(jù)需要后端提供,但是后端提供的這些數(shù)據(jù)可能在很長一段時(shí)間內(nèi)都不會(huì)被修改,比如省市數(shù)據(jù),前端沒必要在每次需要使用這種數(shù)據(jù)時(shí)都請(qǐng)求一次,所以前端可以把該接口的數(shù)據(jù)緩存下來,來節(jié)省請(qǐng)求
對(duì)于這樣的數(shù)據(jù)對(duì)象,也需要保護(hù),簡言之,只要是共用的對(duì)象,均需要防止它被意外的修改
關(guān)于上線前面我們聊到的Safeguard方法,在我看來是沒必要發(fā)布到線上的,只要開發(fā)階段存在即可。只要保證在開發(fā)中沒有對(duì)共享對(duì)象的寫入操作,那么發(fā)布到線上時(shí)肯定也沒有寫入操作,這時(shí)候這個(gè)保護(hù)Safeguard方法就是多余的。
如何在開發(fā)時(shí)保護(hù),而發(fā)布到線上時(shí)去掉呢?
我們可以使用uglify這個(gè)代碼壓縮工具的global_defs配置。比如在開發(fā)階段這樣定義
if (typeof DEBUG == "undefined") window.DEBUG = true; //... const user={ name:"行列", address:{ city:"hz" } } if(DEBUG){ user=Safeguard(user); }
然后在壓縮時(shí):
uglify({ compress: { global_defs: { DEBUG: false } }, output: { ascii_only: true } });
那么這樣壓縮出來的代碼就不包含DEBUG相關(guān)的語句了
當(dāng)然,Safeguard跟隨上線也沒有什么大問題,最后這個(gè)“關(guān)于上線”這塊只是想做更深入的探討,如果Safeguard要上到線上,注意Proxy的兼容即可
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/97350.html
摘要:并發(fā)模塊本身有兩種不同的類型進(jìn)程和線程,兩個(gè)基本的執(zhí)行單元。調(diào)用以啟動(dòng)新線程。在大多數(shù)系統(tǒng)中,時(shí)間片發(fā)生不可預(yù)知的和非確定性的,這意味著線程可能隨時(shí)暫停或恢復(fù)。 大綱 什么是并發(fā)編程?進(jìn)程,線程和時(shí)間片交織和競(jìng)爭條件線程安全 策略1:監(jiān)禁 策略2:不可變性 策略3:使用線程安全數(shù)據(jù)類型 策略4:鎖定和同步 如何做安全論證總結(jié) 什么是并發(fā)編程? 并發(fā)并發(fā)性:多個(gè)計(jì)算同時(shí)發(fā)生。 在現(xiàn)代...
摘要:我們知道在并發(fā)編程中,不能使用多把鎖保護(hù)同一個(gè)資源,因?yàn)檫@樣達(dá)不到線程互斥的效果,存在線程安全的問題。兩個(gè)線程都完成轉(zhuǎn)賬操作后,的賬戶余額可能為,也可能為,但是不可能為。摘要:在編寫多線程并發(fā)程序時(shí),我明明對(duì)共享資源加鎖了啊?為什么還是出問題呢?問題到底出在哪里呢?其實(shí),我想說的是:你的加鎖姿勢(shì)正確嗎?本文分享自華為云社區(qū)《【高并發(fā)】高并發(fā)環(huán)境下詭異的加鎖問題(你加的鎖未必安全)》,作者:冰...
摘要:同一時(shí)刻只有一個(gè)線程執(zhí)行這個(gè)條件非常重要,我們稱之為互斥。那對(duì)于像轉(zhuǎn)賬這種有關(guān)聯(lián)關(guān)系的操作,我們應(yīng)該怎么去解決呢先把這個(gè)問題代碼化。 在前面的分享中我們提到。 一個(gè)或者多個(gè)操作在 CPU 執(zhí)行的過程中不被中斷的特性,稱為原子性 思考:在32位的機(jī)器上對(duì)long型變量進(jìn)行加減操作存在并發(fā)問題,什么原因!? 原子性問題如何解決 我們已經(jīng)知道原子性問題是線程切換,而操作系統(tǒng)做線程切換是依賴 ...
摘要:有的情況下我們希望自己設(shè)計(jì)的類可以讓客戶端程序員們不需要使用額外的同步操作就可以放心的在多線程環(huán)境下使用,我們就把這種類成為線程安全類。 設(shè)計(jì)線程安全的類 前邊我們對(duì)線程安全性的分析都停留在一兩個(gè)可變共享變量的基礎(chǔ)上,真實(shí)并發(fā)程序中可變共享變量會(huì)非常多,在出現(xiàn)安全性問題的時(shí)候很難準(zhǔn)確定位是哪塊兒出了問題,而且修復(fù)問題的難度也會(huì)隨著程序規(guī)模的擴(kuò)大而提升(因?yàn)樵诔绦虻母鱾€(gè)位置都可以隨便使用...
摘要:題記三國時(shí)赤壁鏖戰(zhàn),孔明說,天有不測(cè)風(fēng)云,欲破曹公,宜用火攻,萬事俱備,只欠東風(fēng)。現(xiàn)在公共云混戰(zhàn),我想說,無災(zāi)備不上云,保護(hù)數(shù)據(jù),未雨綢繆,帶了雨傘,還需雨衣。題記:三國時(shí)赤壁鏖戰(zhàn),孔明說,天有不測(cè)風(fēng)云,欲破曹公,宜用火攻,萬事俱備,只欠東風(fēng)。現(xiàn)在公共云混戰(zhàn),我想說,無災(zāi)備不上云,保護(hù)數(shù)據(jù),未雨綢繆,帶了雨傘,還需雨衣。未雨綢繆,到底是帶雨傘還是雨衣呢?時(shí)代在變,人的追求也在變。隨著公共云對(duì)...
閱讀 2471·2021-11-24 09:39
閱讀 3517·2019-08-30 15:53
閱讀 593·2019-08-29 15:15
閱讀 2902·2019-08-26 13:23
閱讀 3211·2019-08-26 10:48
閱讀 642·2019-08-26 10:31
閱讀 747·2019-08-26 10:30
閱讀 2358·2019-08-23 18:32