2023年12月13日 星期三
有趣的小東西MutationObserver
2023年12月10日 星期日
proxy遇到lagacy browser的小坑
前言
還記得前幾天我用signal包了react用的vue hook套件嗎?才講完沒試過兩天就出事了
不過好里加在不是什麼大包,事情是這樣的
內文
有個Android 8 chrome 70 webview的用戶(簡單說就是android的webview)回報資料顯示有問題,我看這版本起碼也是七八年前的產品,但照道理來說都已經支援Proxy了怎麼可能會出什麼大錯,再track bug的過程中發現,我寫的資料陣列被過濾掉了
我在console.log(payment)都是有東西的,理論上應該都要找得到相對應物件,但為什麼會被filter掉,所以我試著不要filter直接在console.log出來,發現問題出在{...x}擴展運算子並沒有生效!!
難道是老舊瀏覽器不支援這ES6語法?所以我又隨便寫了一個
發現這樣寫是正常的,所以應該只是因為Proxy,所以多了一層,然後擴展運算子當時還不支援擴展Proxy,94這麽簡單。那這樣要怎麼搞定呢?
我嘗試一下Object.assign還是可以把Proxy擴展出來,所以就改成這樣
OK打玩收工
後記
過程中我有嘗試用lagacy plugin把程式碼轉成es5但似乎都沒有成功,vite似乎不希望程式碼可以編譯到es6以下,總之vite還是有他不方便的地方啊,祝大家都可以準時下班~
2023年12月9日 星期六
針對某公司前端面試做個紀錄
前言
我絕對不會說我去面試K什麼M什麼體什麼X的公司,整體面試感受不太好
HR不夠積極跟友善,面試前一小時臨時改面試時間,面試開始前八分鐘才叫我提前五分鐘到,結果面試官也是準點進來,然後面試官整場用我不熟悉的語法(純粹大陸用語跟台灣用語不同)來問問題,所以很多問題我也只能重複進行確認,然後問完話也沒有要讓我提問,說沒有問題了匆匆結束會議,然後也沒有打算讓我跟HR二面,就在你問我答,足足問了22分鐘結束面試....好吧,非常有效率給你一個讚!
內文
針對被問幾個我印象比較深刻或回答沒這麼好的問題進行一次紀錄
1. 輸入網址到畫面渲染,中間過程如何....
又是這種沒有標準答案的鳥問題
2.vue v-for跟v-if可以一起用嗎?
我回答可以,對方接著問誰先誰後,我說太久沒用我忘了,試過就知道(但對方顯然對這答案不買單)
最近去翻筆記,確實是可以,然後在底層v-for會先執行再執行v-if
3.js的垃圾回收機制是什麼?
老實說我會寫不會記憶體洩漏的程式,所以從來沒想過這問題,所以我去查一下
答案是沒有被引用的物件會被瀏覽器回收,所以如果有物件相互引用就會造成記憶體洩漏(memory leaks)
4.Promise的狀態有什麼?
又是一題會寫但不知道答案的問題,我用這麼久還沒遇過有人問這問題,去查一下答案是
pending執行中
reject操作失敗
resolve操作成功
5.react useRef可以用來幹嘛
記錄變數,指向DOM
6.react useState, useRef,當state更新但畫面沒有更新,可以透過ref回復到先前狀態嗎?
我回答:理論上是可以啊。對方突然很驚訝回我:可以!那要怎麼做。我:就看你邏輯怎麼寫吧...他的回答讓我感覺我的回答是錯的,這就是沒有程式碼在那邊盲問的缺點,另外我倒是很想問你是怎麼做到更新state然後畫面沒有更新
小結
其實他還問了很多,但大多我都會答,應該是都對拉,雖然最後我被打上T3的等級(對方要T4),然後被大砍期待薪資,不過貴公司996的工作時數我就算沒被砍我也大概率不會進去(是真的996),然後工時打在JD上我以為是常識,只能說我真的孤陋寡聞,還是在我面試完後拼命追問HR才告訴我。只能說這間公司除了遠端,其他沒有任何一點吸引我的地方
2023年12月8日 星期五
nginx X-Frame-Options & proxy
add_header X-Frame-Options DENY;proxy_pass http://$host;upstream a_node_app {
server 127.0.0.1:3011;
}2023年12月3日 星期日
我受夠了react的hook,我想寫vue啊~
前言
你是否有跟我一樣的困擾呢,覺得react class component的setState寫法相當繁瑣,覺得react hook的的queue也不夠直覺,為什麼不能直接update state然後畫面就自動render需要透過一個setter,然後資料異動還不是同步的,也不是異步,竟然是透過queue......這是我一直以來的心聲。我今天沒有要戰,純粹是就職以來的一些小心得,作為一套老牌框架,我承認他的市佔率,但我覺得如果以便利性讓我挑選,我一定不會選react,但礙於現有的社群要他大改幾乎是不太可能,就算不論三大框架現在市場上也充斥著太多套創新的框架(qwik, svelte, solid, astro....),所以要用一個形容詞來形容這套框架只能說它“過時”了,but!最可怕的but來了,公司就愛用嘛~所以有沒有什麼辦法?
老實說我很驚訝竟然查不到相關的資料,還是大家都超滿意react,沒遇到什麼奇怪的坑,我是異類,總之~辦法還是有的,首先我在腦海中搜索想到了奶綠茶有介紹過preact/signal,奶綠大大事我很喜歡的一位工程師,我大學時還買過他的書,不過那是另外一個故事了
內文
preact跟react是不一樣的框架,但其中的api友87%像,signal使用起來就像是vue裡面的ref(太詳細的內容自己去看原始碼),然後看網誌說明signal無法直接使用在react,特別是底層是vite打包的狀況下(該死)
所以不得已我又開始尋找其他法,後來發現preact/signal有出preact/react-signal特別優化的版本,這樣應該是妥了吧,官方都直接出優化了,直接使用在公司專案結果爆出getSnapshop is undefined......我去查了一下原始碼也一無所獲,歸功於react亂七八糟......抱歉我不該戰,是莫名其妙...抱歉,是我孤陋寡聞不得而知的底層運作機制,所以我放棄了這麼一條路
難道我就該止步於此繼續使用這該死又難寫......抱歉我不該戰,我要繼續使用這我用了很痛苦的框架嗎?當然不是,既然連官方都靠不住,那就只能自己來寫了,一開始我嘗試使用Object.defineProperty去寫(沒錯就是vue2那套,想看原始碼也附註解在裡面),反正所有東西都丟到value下面就好了吧,但也發生了跟vue2一樣的問題,沒有註冊過的屬性就不會reactive,但如果使用Proxy怕太新UC那些奇怪的瀏覽器不支援
沒錯公司要求產品要支援UC,講到這裡我想花一點篇幅抱怨一下,建議看到這裡的工程師,珍惜生命,遠離UC,下次面試記得要問主管公司有沒有要求要支援UC,有人說UC就像手幾板的ie我覺得他說錯了,他比ie還不如!不僅沒辦法debug,之前發生一次白屏,在我一行一行除錯,最後問題竟然是html排序它不滿意,不是什麼沒有加上</>這種低級錯誤喔,就是單純排序它不滿意,當時的狀況就類似以下:
<div>
hello
<div>hello2</div>
<div>
然後我把它改成
<div>hello<div>
<div>hello2</div>
就正常了.....我還以為我又用什麼新的寫法或物件戳到它的G點,Fuck!這我真的沒辦法誒!!
好拉,工作還是要繼續下去,但這還在研發階段之不支援我就先不考慮,之後不支援大不了不用!所以你以為我就乖乖刻輪子嗎?當然沒有,我想到既然底層都是Proxy那我用signal就好拉,那畫面不會reactive的問題怎麼處理?奶綠茶大大的網誌有提到react18有出一個新的hook是useSyncExternalStore 這個hook可以控制畫面要不要渲染,網誌裡面有提到大大如何包裝這個function,我試著去改寫但我一直嘗試不成功,因為我一直把變數放在function內,所以在rerender時function會重跑一遍,所以變數每次都會被重置(Fuck我就說寫法很不直覺吧),當我想到這問題時已經好幾天過去了,如果不想變數被重置,那就使用原生的hook來解決吧,最後產出來的code就如下
沒錯,前面說這麼多我只是想要抱怨,最終結果在下面,大家如果為了自己身體著想,可以直接拿去使用
我模擬出一些比較常用的hook,其他我也很少用就不做了,畢竟這就像那些砲轟我的網友說的,就是vue皮react骨,我也沒有不承認這件事,但更新資料畫面就會自動更新就是爽,也不用在那邊setState後還要在useEffect等狀態更新才能在function裡面執行我想執行的內容,這寫法真的很蠢......抱歉我不該戰,這寫法真的很不直覺
好吧廢話不多說直接上程式碼
這樣onMounted, onUnmounted也解決了useEffect裡面不能放async的function,那警告看了真的很礙眼,支援就不要吵,不支援就直接抱錯,在那邊吵什麼吵,然後為什麼不多包一層就好,我也不知道,可能礙於什麼東方神秘力量
reactive就直接用別人寫好的吧
watch就是watch
computed這麼好用的功能怎麼能不實現(但我沒實現getter、setter,沒錯因為我不常用)
ref就用useRef去解決變數被重置問題,我們來比較一下差別
// normal way
const [value, setValue] = useState(0)
setValue(1)
console.log(value) // 0 wtf!
useEffect(() => {
console.log(value) // 1
}, [value])
// better way
const [value, setValue] = useState(0)
const newValue = 1
setValue(newValue)
console.log(newValue) // 1 .....why so troublesome?
// new way
const state = ref(0)
state.value++
console.log(state.value) // 1
// 484很直覺!484很爽!484很好寫
後記
最重要UC, QQ這些中國大牌瀏覽器到底有沒有支援Proxy呢~~答案是有的,至少上線到現在沒有傳出什麼災情
謎之聲:連Promise.race跟any都可以拔掉,竟然支援Proxy,真是可喜可賀~
不過想想也是拉,現在vue3都用Proxy寫了,如此泱泱大國總不會想跟自國工程師對著幹吧!
最後,我沒有實際測過使用起來的效能,我相信應該不會太好,畢竟有內容更新畫面就要重新渲染一次,原本react18 queue的優化都沒用了,但我才不管,開發體驗最重要!!事實上,你如果注重效能就不會選擇react框架了,那這篇就先到這裡拉,希望大家都可以準時下班,see u later~
12/18更新
computed並非是及時的,useSyncExternalStore只用來更新畫面,所以如果要用在邏輯演算中,用useMemo效果可能比較好,之後再來思考看有沒有機會debug,下面有個使用範例,這真令人有點難過
const users = [{ birthday: 2020-01-01}, {birthday:"2022-02-02"}]
let index = 0
const user = computed(() => users[index].birthday)
console.log(user.birthday) // 2020-01-01
index = 1
console.log(user.birthday) // 2020-01-01 來不及更新
2023年11月20日 星期一
vue2 event hook destroyed
在官方建議寫法一般是這樣
但你也可以這樣寫
這樣寫有什麼好處呢,主要防止邏輯四散,每個人寫作習慣不同,mounted跟destroyed不一定就在旁邊,有人mounted會寫一大串,最造成閱讀上沒這麼直覺。你可以在宣告偵聽時就確定他會在component destroyed時被取消偵聽減少資源浪費。這寫法就跟golang的defer類似。
其實早在很久前就有這樣寫了,只是沒記下來真的會忘記,到最近又碰到vue想要寫才把這招翻出來,所以就做個紀錄
2023年10月26日 星期四
docker,或者說docker-compoes踩的小坑,nginx host name指向問題
先附上我寫的docker-compose
情境說明
我在構思前後端架構時,後端用nodejs,然後前端用nginx,這沒什麼問題,然後因為要走ssl,我懶得把ssl key也copy到後端專案,打算直接在nginx用proxy的方式做掉,OK事情就是這樣發生了,先附上docker-compose跟nginx設定
這一切乍看之下都很完美,但實際在打https://127.0.0.1:3333卻會報502,意思就是打不到東西,我一開始是想是不是node-api讀不到的關係,查了很多關於links, depends_on, networks的文件,最後進到nginx container裡面實際下指令nslookup node-api也確實有,ping也ping得到
Server: 127.0.0.11
Address: 127.0.0.11:53
Non-authoritative answer:
Non-authoritative answer:
Name: node-api
Address: 172.23.0.2
後來我發現,我啟動的container也只有兩個,但ip卻有三個
172.23.0.1
172.23.0.2 <= node-api
172.23.0.3 <= nginx
ok問題來了,照上面指令2應該就是node-api,3應該是nginx,那1是什麼呢?我繼續下指令curl -G http://172.23.0.1:8000
矮油這下問題嚴重了,我一度以為docker出問題,把host name指向錯誤的主機,想上網找但關鍵字也不知道怎麼下
後來在苦無對策之際,最後試著下一個指令
一切都真相大白了,我一直以為container是在各自的容器(我不知道這專有名詞是啥,只是講container會搞混,在我想像中他形式比較像沙箱跟區網的概念,將箱子也不好聽,所以就叫中文的容器吧),藉由expose把port開出來讓外界使用,事實上如果用docker-compose那大家就會在同一個容器內,所以網內互打是打原本的port不是export的port,所以1應該就是最後所有container的集合....吧,所以最終只要這樣修改就好。
因此最終node-api的ports設定也可以拿掉。
我也不是專業的devpos,就是專案需要所以簡單地摸了一下,踩了坑就記錄一下,歡迎不大家吝嗇指教,只是希望可以噴得小力一點!