UI Event 的順序

othree 寫了一篇「UI Event Order」在講滑鼠 (或是更廣廣義的 pointer 類) 以及鍵盤 (包括輸入法) 在瀏覽器上會產生的 event。

裡面有些是歷史 (提到 IE 上的實作方式),現在都不太會碰到了,可以直接看目前的幾份標準就好,然後蠻多標準都還是在 draft 階段,各家瀏覽器更新的速度不一樣,所以會有不同的行為冒出來。

我決定先把文章保留起來,等遇到的時候再回來看 XD

查詢 GitHub 上面 repository 的公開記錄

起因應該是「Claim: Private GitHub repos included in AI dataset (lurk.org)」這邊的討論,原文是 @emenel@post.lurk.orghttps://post.lurk.org/@emenel/112111014479288871 這邊宣稱他在 GitHub 的 private repository 被當作 training data 蒐集走使用。

而 GitHub 有公開全站的 public event data,所以 Simon Willison 就拿這份資料直接組了一個工具出來用:「GitHub Public repo history」。

這樣可以直接 auditing 對應的說法,不過看了一下 GitHub 上的帳號 emenel (上面連結是到同一個站,應該是同一個人),目前看起來已經把所有 repository 都刪掉了...

Keyboard Event:在網頁上自定義快速鍵

先前寫了一堆 userscript 針對不同的網站加上快速鍵 (像是翻下一頁或是上一頁):

然後發現太多重複的事情了,就寫成 Chrome 的 extension 了:「Keyboard Event」,程式碼在 GitHub 上有放:「gslin/keyboard-event」,不信任一致性的話也可以用 Chrome extension source viewer 直接看 chrome web store 上面放的版本。

這個 extension 的想法是設定 hostname、path 以及按鍵,接著設定按鍵按下後會觸發的 DOM element (用 CSS selector 選) 與 DOM event (像是 mouseover 這樣的 event 字串)。

而其中 click event 常常不會動 (對應實際的呼叫是 element.dispatchEvent(new Event('click'))),在 debug 時發現需要用 click() (對應實際的呼叫是 element.click()),所以有特別接受 click() 這個字串。

這個舉個例子,我有一組設定是:

www.instagram.com
.*
<
div[role="dialog"] button[aria-label="Go back"]
click()

www.instagram.com
.*
>
div[role="dialog"] button[aria-label="Next"]
click()

在瀏覽器上面看 Instagram 的照片時可以用 <> 快速切換照片。

另外設定的部分支援 chrome.storage 的 browser sync,對於有多瀏覽器時會自動同步設定檔,不用每一台都設定一次...

這算是第一次寫 Manifest V3 的 extension (先前都是 V2),本來想用 Vue.js 處理設定頁 options.html,但遇到了 CSP 的問題,在 Manifest V3 上面無法設定 unsafe-eval,於是 Vue.js 只能用 runtime 版本,喪失了 template 好用的地方...

後來決定回頭用 jQuery + jQuery UI (用 sortable),然後自己處理一堆 data 更新時頁面的變化,一整個 2010 年老人味都出來了...

但這樣至少會動,先跑一陣子看看...

uBlock Origin 可以修改 DOM event

Hacker News 上看到的「Just normal web things (heather-buchel.com)」這篇,原文「Just normal web things.」本來在抱怨一些 SPA 年代常遇到的問題,但我注意到的反而是討論裡的 id=37018421 這則,介紹了 uBlock Origin 可以修改特定的 DOM event:

New Reddit also messes with text selection with unnecessary JS crap. Wherever you select some text, they show an "Embed" button that prevents you from dragging the text to a new tab to perform a web search.

Thankfully this behaviour can be blocked with uBlock Origin by adding these rules:

  www.reddit.com##+js(aeld, mousedown, isSelectionOutOfRange)
  www.reddit.com##+js(aeld, mouseup, shouldShowButton)

翻了 uBlock Origin 的 wiki 文件,這應該是 aeld.js / addEventListener-defuser.js 這個功能:

Prevents attaching event listeners.

aeld 可以阻止某些事件掛到 DOM 元素上,這感覺好像可以少寫不少 userscript,單純用 uBlock Origin 設條件就可以做到了?

另外在同一頁上 (Resources Library 這頁) 也有其他有趣的東西,像是拔掉 timeout 設定或是某些 attribute 的內容,另外也可以對 API 傳回來的 JSON 或 XML 內容進行刪除某些欄位...

算是意外注意到,後續希望遇到的時候可以想起來...

改善 Wikipedia 的 JavaScript,減少 300ms 的 blocking time

Hacker News 首頁上看到「300ms Faster: Reducing Wikipedia's Total Blocking Time」這篇,作者 Nicholas RayWikimedia Foundation 的工程師,雖然是貼在自己的 blog 上,但算是半官方性質了... 文章裡面提到了兩個改善都是跟前端 JavaScript 有關的。

作者是透過瀏覽器端的 profiling 產生火焰圖,判讀裡面哪塊是大塊的問題,然後看看有沒有機會改善。

先看最後的成果,可以看到第一個 fix 讓 blocking time 少了 200ms 左右,第二個 fix 則是少了 80ms 左右:

第一個改善是從火焰圖發現 l._enable 吃掉很多 blocking time:

作者發現是因為 find() 找出所有的連結後 (a 元素),跑去每一個連結上面綁定事件造成的效能問題:

The .on("click") call attached a click event listener to nearly every link in the content so that the corresponding section would open if the clicked link contained a hash fragment. For short articles with few links, the performance impact was negligible. But long articles like ”United States” included over 4,000 links, leading to over 200ms of execution time on low-end devices.

但這其實是 redundant code,在其他地方已經有處理了,所以解法就比較簡單,拔掉後直接少了 200ms:

Worse yet, this behavior was unnecessary. The downstream code that listened to the hashchange event already called the same method that the click event listener called. Unless the window’s location already pointed at the link’s destination, clicking a link called the checkHash method twice — once for the link click event handler and once more for the hashchange handler.

第二個改善是 initMediaViewer 吃掉的 blocking time,從 code 也可以看到問題也類似,跑一個 loop 把事件掛到所有符合條件的元素上面:

這邊的解法是 event delegation,把事件掛到上層的元素,就只需要掛一個,然後多加上檢查事件觸發的起點是不是符合條件就可以了,這樣可以大幅降低「掛」事件的成本。

這點算是常用技巧,像是 table 裡面有事件要掛到很多個 td 的時候,會改成把一個事件掛到 table 上面,另外加上判斷條件。

算是蠻標準的 profiling 過程,直接拉出真實數據來看,然後調有重大影響的部分。

瀏覽器裡同一個節點上 JavaScript 的事件觸發順序

瀏覽器裡 JavaScript 的事件觸發順序是先 capture 再 bubble,這個在「Event order」這邊就有一些歷史解釋,IE8 以前只有 capture 模式,到了 IE9+ 才支援,在「Event API: bubbles」這邊也可以看到。

但如果是同一個節點上面的事件觸發順序 (假設同樣是 capture 或是同樣是 bubble),在「Are event handlers in JavaScript called in order?」這邊有些整理資料。

2000 年的「Document Object Model (DOM) Level 2 Events Specification」這邊提到沒有定義順序:

When the event reaches the target, any event listeners registered on the EventTarget are triggered. Although all EventListeners on the EventTarget are guaranteed to be triggered by any event which is received by that EventTarget, no specification is made as to the order in which they will receive the event with regards to the other EventListeners on the EventTarget.

在早期的 draft「Document Object Model (DOM) Level 3 Events Specification」裡面可以看到:

Next, the implementation must determine the current target's candidate event listeners. This must be the list of all event listeners that have been registered on the current target in their order of registration. [HTML5] defines the ordering of listeners registered through event handler attributes.

但在最新的「UI Events」(要注意這還是 draft,在 2016 年更新的) 則是拿掉了這段。

所以在設計架構時,正常還是得保守的假設沒有保證執行順序...

Vector clock 的發明時間軸

一樣是在 Hacker News 上看到「Who invented vector clocks? (decomposition.al)」這篇文章,在找出誰發明了 vector clock,原文在「Who invented vector clocks?」。

主要有兩個不同的時間點,一個是 vector clock 概念的提出,另外一個是第一次用到 vector 這個詞。

這篇讓我覺得有趣的地方是,vector clock 本來就是在處理分散式系統裡面事件順序的問題,而這篇文章則是在找出真實世界裡面這些發明的先後順序,而且也牽扯到了各種 citation (類比到分散式系統裡事件的 dependency)。

分散式系統的 clock

前幾天在 Hacker News 上看到「Clocks and Causality – Ordering Events in Distributed Systems (2022) (exhypothesi.com)」這篇,講分散式系統上 clock 的設計,作者也有跑出來在 Hacker News 上面跟大家聊一下 (帳號是 thoughtlede),原文在「Clocks and Causality - Ordering Events in Distributed Systems」這邊。

文章裡面主要講空間是 O(1)Lamport timestamp 與空間是 O(n)Vector clock (這邊的 n 相對於節點數量),以及這兩個對應的擴充版本:

作者會整理這些資料的原因是因為在研究 CRDT 的時候看到演算法中常常會需要處理分散式系統裡面事件的順序,所以花了一些時間整理常見的方式:

Author here. Pleasantly surprised to see the article here.

Some context behind the article. I studied CRDTs for a few months, and noticed that different CRDT designs use logical clocks in different and clever ways. And I haven't seen anyone narrate all those ways of use in one article. My attempt with this article was to dredge up those flavors of logical clocks into one article and give them names for future reference.

(To respond to a couple of other comments, I ignored atomic (and gps-based) clocks in this discussion, as indicated in my footnote 3).

我記得還有一個 Interval Tree Clocks 可以參考 (在「Interval Tree Clocks」這邊講的比較清楚),是針對節點的動態增刪而改善的演算法,但不確定有什麼比較有名的系統有用。

大多數應該都是用 Vector clock,畢竟是在 2007 年的「Dynamo: Amazon’s Highly Available Key-value Store」被發揚光大,而且也算是還不錯的演算法?

QTE 小遊戲 Looptap

Hacker News 首頁上看到這個小遊戲:「Show HN: Looptap – A minimal game to waste your time (vasanthv.com)」,如同他的標題寫的,浪費時間的小遊戲 XDDD

標題講的 QTE 是「快速反應事件」這個東西,在現在的遊戲裡面算是蠻常見的機制,是一種需要在事件有效區間反應的設計 (太早反應或是太晚反應都不行)。

前幾天 AWS 的 us-east-1 出事報告

AWS 放出前幾天 us-east-1 出事的報告了:「Summary of the AWS Service Event in the Northern Virginia (US-EAST-1) Region」,Hacker News 上的討論「Summary of the AWS Service Event in the Northern Virginia (US-East-1) Region (amazon.com)」也可以看一下,裡面也有人提到儘量閃開 us-east-1

而爆炸當天的討論「AWS us-east-1 outage (amazon.com)」也可以看一看,裡面還有聊到企業文化的問題...

AWS 的 us-east-1 除了是 AWS 最早的區域以外,也是目前 AWS 內功能最多的區域 (大多數新功能在第一波都會開放 us-east-1 使用),然後也是最便宜的區域,所以會有很多人都用這個區域提更服務。

也因為這樣,這個區域也是 AWS 內最大的區域,加上 AWS 是目前最大的公有雲,導致了這個區域的很多東西會遇到以前的人都沒遇過的問題,大概每年 (或是每兩年) 就會有一次比較嚴重的 outage,算是為了價錢而選擇 us-east-1 的人要注意的。

說到價錢,如果是為了找價錢比較低的區域,另外一個可以考慮選擇是 us-west-2,出新功能與新產品時也常常會被放進第一波,目前看起來的歷史記錄應該是比 us-east-1 好不少...

這次出問題的主要是內部控制用的網路 (被稱為 internal network) 擁塞,而非客戶在用的網路 (被稱為 main network):

To explain this event, we need to share a little about the internals of the AWS network. While the majority of AWS services and all customer applications run within the main AWS network, AWS makes use of an internal network to host foundational services including monitoring, internal DNS, authorization services, and parts of the EC2 control plane.

後面也有提到因為壅塞而導致 monitoring 系統受到影響,只能就手上的 log 去分析猜測,然後逐步排除問題,而 deployment 系統也使用內部網路,所以更新的速度也快不起來...

不過基本上可以預期明年或是後年應該還是會再來一波...