Greasy Fork is available in English.
A lightweight, dependency-free mutex for Userscripts that ensures **only one tab / context** runs a critical section at a time. It coordinates through `GM.setValue` + `GM_addValueChangeListener`, so it works across multiple tabs, iframes, and even separate scripts that share the same @name/@namespace storage.
当前为
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.greasyfork.icu/scripts/554436/1687613/GM_lock.js
A lightweight, dependency-free mutex for Userscripts that ensures only one tab / context runs a critical section at a time. It coordinates through GM.setValue + GM_addValueChangeListener, so it works across multiple tabs, iframes, and even separate scripts that share the same @name/@namespace storage.
Userscripts often run in several places at once (multiple tabs, iframes, reruns). If you have code that must not run concurrently (e.g., rate-limited API calls, queue processing, cache writes), GM_lock(tag, fn) makes that section execute exclusively.
Just copy the function into your script (or @require it, if you publish as a library). Requires a manager that supports:
GM.setValue, GM.listValues, GM.deleteValueGM_addValueChangeListener, GM_removeValueChangeListenerTested with Tampermonkey, Violentmonkey and ScriptCat. (Greasemonkey 4+ may require adapting API names.)
await GM_lock(tag: string, func: () => (Promise<any> | any)): Promise<any>
func’s result/error.// Only one instance across all tabs will enter this block at a time
await GM_lock('sync-cache', async () => {
const data = await fetch('https://api.example.com/data').then(r => r.json());
await GM.setValue('cache:data', data);
});
GM_lock::<tag>::<lockId> and announces via GM_lock_changed::<tag>.GM_addValueChangeListener.func.This design avoids busy-waiting: it’s event-driven and cross-context.
func can throw/reject; that error bubbles out of GM_lock.func for long periods; prefer awaiting async work.MIT — do whatever, just keep the notice.