protect<T> static method
Guarantees the callback
is invoked synchronously, only by single tab or
code block at the same time.
Implementation
static Future<T> protect<T>(
Future<T> Function() callback, {
bool exclusive = true,
String tag = 'mutex',
}) async {
Mutex? mutex = exclusive ? _guards[tag] : Mutex();
if (mutex == null) {
mutex = Mutex();
_guards[tag] = mutex;
}
return await mutex.protect(() async {
// Web Locks API is unavailable for some reason, so proceed without it.
if (!_locksAvailable()) {
return await callback();
}
final Completer<T> completer = Completer();
JSPromise function(JSAny? any) {
return callback()
.then((val) => completer.complete(val))
.onError(
(e, stackTrace) =>
completer.completeError(e ?? Exception(), stackTrace),
)
.toJS;
}
try {
await _requestLock(
tag,
{'mode': exclusive ? 'exclusive' : 'shared'}.jsify() as JSObject,
function.toJS,
).toDart;
} catch (e) {
// If completer is completed, then the exception is already handled.
if (!completer.isCompleted) {
rethrow;
}
}
return await completer.future;
});
}