mirror of
https://github.com/bitwarden/browser
synced 2025-12-12 22:33:35 +00:00
[PM-14999] Remove Sequentialize (#12113)
* Remove Sequentialize * Delete `clearCaches`
This commit is contained in:
@@ -115,7 +115,6 @@ import { Message, MessageListener, MessageSender } from "@bitwarden/common/platf
|
|||||||
// eslint-disable-next-line no-restricted-imports -- Used for dependency creation
|
// eslint-disable-next-line no-restricted-imports -- Used for dependency creation
|
||||||
import { SubjectMessageSender } from "@bitwarden/common/platform/messaging/internal";
|
import { SubjectMessageSender } from "@bitwarden/common/platform/messaging/internal";
|
||||||
import { Lazy } from "@bitwarden/common/platform/misc/lazy";
|
import { Lazy } from "@bitwarden/common/platform/misc/lazy";
|
||||||
import { clearCaches } from "@bitwarden/common/platform/misc/sequentialize";
|
|
||||||
import { Account } from "@bitwarden/common/platform/models/domain/account";
|
import { Account } from "@bitwarden/common/platform/models/domain/account";
|
||||||
import { GlobalState } from "@bitwarden/common/platform/models/domain/global-state";
|
import { GlobalState } from "@bitwarden/common/platform/models/domain/global-state";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
@@ -1442,8 +1441,6 @@ export default class MainBackground {
|
|||||||
await this.popupViewCacheBackgroundService.clearState();
|
await this.popupViewCacheBackgroundService.clearState();
|
||||||
await this.accountService.switchAccount(userId);
|
await this.accountService.switchAccount(userId);
|
||||||
await switchPromise;
|
await switchPromise;
|
||||||
// Clear sequentialized caches
|
|
||||||
clearCaches();
|
|
||||||
|
|
||||||
if (userId == null) {
|
if (userId == null) {
|
||||||
await this.refreshBadge();
|
await this.refreshBadge();
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import {
|
|||||||
AbstractStorageService,
|
AbstractStorageService,
|
||||||
StorageUpdate,
|
StorageUpdate,
|
||||||
} from "@bitwarden/common/platform/abstractions/storage.service";
|
} from "@bitwarden/common/platform/abstractions/storage.service";
|
||||||
import { sequentialize } from "@bitwarden/common/platform/misc/sequentialize";
|
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { NodeUtils } from "@bitwarden/node/node-utils";
|
import { NodeUtils } from "@bitwarden/node/node-utils";
|
||||||
|
|
||||||
@@ -44,7 +43,6 @@ export class LowdbStorageService implements AbstractStorageService {
|
|||||||
this.updates$ = this.updatesSubject.asObservable();
|
this.updates$ = this.updatesSubject.asObservable();
|
||||||
}
|
}
|
||||||
|
|
||||||
@sequentialize(() => "lowdbStorageInit")
|
|
||||||
async init() {
|
async init() {
|
||||||
if (this.ready) {
|
if (this.ready) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag
|
|||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
import { SystemService } from "@bitwarden/common/platform/abstractions/system.service";
|
import { SystemService } from "@bitwarden/common/platform/abstractions/system.service";
|
||||||
import { clearCaches } from "@bitwarden/common/platform/misc/sequentialize";
|
|
||||||
import { NotificationsService } from "@bitwarden/common/platform/notifications";
|
import { NotificationsService } from "@bitwarden/common/platform/notifications";
|
||||||
import { StateEventRunnerService } from "@bitwarden/common/platform/state";
|
import { StateEventRunnerService } from "@bitwarden/common/platform/state";
|
||||||
import { SyncService } from "@bitwarden/common/platform/sync";
|
import { SyncService } from "@bitwarden/common/platform/sync";
|
||||||
@@ -406,8 +405,6 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||||||
this.router.navigate(["/remove-password"]);
|
this.router.navigate(["/remove-password"]);
|
||||||
break;
|
break;
|
||||||
case "switchAccount": {
|
case "switchAccount": {
|
||||||
// Clear sequentialized caches
|
|
||||||
clearCaches();
|
|
||||||
if (message.userId != null) {
|
if (message.userId != null) {
|
||||||
await this.accountService.switchAccount(message.userId);
|
await this.accountService.switchAccount(message.userId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,139 +0,0 @@
|
|||||||
import { clearCaches, sequentialize } from "./sequentialize";
|
|
||||||
|
|
||||||
describe("sequentialize decorator", () => {
|
|
||||||
it("should call the function once", async () => {
|
|
||||||
const foo = new Foo();
|
|
||||||
const promises = [];
|
|
||||||
for (let i = 0; i < 10; i++) {
|
|
||||||
promises.push(foo.bar(1));
|
|
||||||
}
|
|
||||||
await Promise.all(promises);
|
|
||||||
|
|
||||||
expect(foo.calls).toBe(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should call the function once for each instance of the object", async () => {
|
|
||||||
const foo = new Foo();
|
|
||||||
const foo2 = new Foo();
|
|
||||||
const promises = [];
|
|
||||||
for (let i = 0; i < 10; i++) {
|
|
||||||
promises.push(foo.bar(1));
|
|
||||||
promises.push(foo2.bar(1));
|
|
||||||
}
|
|
||||||
await Promise.all(promises);
|
|
||||||
|
|
||||||
expect(foo.calls).toBe(1);
|
|
||||||
expect(foo2.calls).toBe(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should call the function once with key function", async () => {
|
|
||||||
const foo = new Foo();
|
|
||||||
const promises = [];
|
|
||||||
for (let i = 0; i < 10; i++) {
|
|
||||||
promises.push(foo.baz(1));
|
|
||||||
}
|
|
||||||
await Promise.all(promises);
|
|
||||||
|
|
||||||
expect(foo.calls).toBe(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should call the function again when already resolved", async () => {
|
|
||||||
const foo = new Foo();
|
|
||||||
await foo.bar(1);
|
|
||||||
expect(foo.calls).toBe(1);
|
|
||||||
await foo.bar(1);
|
|
||||||
expect(foo.calls).toBe(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should call the function again when already resolved with a key function", async () => {
|
|
||||||
const foo = new Foo();
|
|
||||||
await foo.baz(1);
|
|
||||||
expect(foo.calls).toBe(1);
|
|
||||||
await foo.baz(1);
|
|
||||||
expect(foo.calls).toBe(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should call the function for each argument", async () => {
|
|
||||||
const foo = new Foo();
|
|
||||||
await Promise.all([foo.bar(1), foo.bar(1), foo.bar(2), foo.bar(2), foo.bar(3), foo.bar(3)]);
|
|
||||||
expect(foo.calls).toBe(3);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should call the function for each argument with key function", async () => {
|
|
||||||
const foo = new Foo();
|
|
||||||
await Promise.all([foo.baz(1), foo.baz(1), foo.baz(2), foo.baz(2), foo.baz(3), foo.baz(3)]);
|
|
||||||
expect(foo.calls).toBe(3);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return correct result for each call", async () => {
|
|
||||||
const foo = new Foo();
|
|
||||||
const allRes: number[] = [];
|
|
||||||
|
|
||||||
await Promise.all([
|
|
||||||
foo.bar(1).then((res) => allRes.push(res)),
|
|
||||||
foo.bar(1).then((res) => allRes.push(res)),
|
|
||||||
foo.bar(2).then((res) => allRes.push(res)),
|
|
||||||
foo.bar(2).then((res) => allRes.push(res)),
|
|
||||||
foo.bar(3).then((res) => allRes.push(res)),
|
|
||||||
foo.bar(3).then((res) => allRes.push(res)),
|
|
||||||
]);
|
|
||||||
expect(foo.calls).toBe(3);
|
|
||||||
expect(allRes.length).toBe(6);
|
|
||||||
allRes.sort();
|
|
||||||
expect(allRes).toEqual([2, 2, 4, 4, 6, 6]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return correct result for each call with key function", async () => {
|
|
||||||
const foo = new Foo();
|
|
||||||
const allRes: number[] = [];
|
|
||||||
|
|
||||||
await Promise.all([
|
|
||||||
foo.baz(1).then((res) => allRes.push(res)),
|
|
||||||
foo.baz(1).then((res) => allRes.push(res)),
|
|
||||||
foo.baz(2).then((res) => allRes.push(res)),
|
|
||||||
foo.baz(2).then((res) => allRes.push(res)),
|
|
||||||
foo.baz(3).then((res) => allRes.push(res)),
|
|
||||||
foo.baz(3).then((res) => allRes.push(res)),
|
|
||||||
]);
|
|
||||||
expect(foo.calls).toBe(3);
|
|
||||||
expect(allRes.length).toBe(6);
|
|
||||||
allRes.sort();
|
|
||||||
expect(allRes).toEqual([3, 3, 6, 6, 9, 9]);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("clearCaches", () => {
|
|
||||||
it("should clear all caches", async () => {
|
|
||||||
const foo = new Foo();
|
|
||||||
const promise = Promise.all([foo.bar(1), foo.bar(1)]);
|
|
||||||
clearCaches();
|
|
||||||
await foo.bar(1);
|
|
||||||
await promise;
|
|
||||||
// one call for the first two, one for the third after the cache was cleared
|
|
||||||
expect(foo.calls).toBe(2);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
class Foo {
|
|
||||||
calls = 0;
|
|
||||||
|
|
||||||
@sequentialize((args) => "bar" + args[0])
|
|
||||||
bar(a: number): Promise<number> {
|
|
||||||
this.calls++;
|
|
||||||
return new Promise((res) => {
|
|
||||||
setTimeout(() => {
|
|
||||||
res(a * 2);
|
|
||||||
}, Math.random() * 100);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@sequentialize((args) => "baz" + args[0])
|
|
||||||
baz(a: number): Promise<number> {
|
|
||||||
this.calls++;
|
|
||||||
return new Promise((res) => {
|
|
||||||
setTimeout(() => {
|
|
||||||
res(a * 3);
|
|
||||||
}, Math.random() * 100);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
|
||||||
// @ts-strict-ignore
|
|
||||||
const caches = new Map<any, Map<string, Promise<any>>>();
|
|
||||||
|
|
||||||
const getCache = (obj: any) => {
|
|
||||||
let cache = caches.get(obj);
|
|
||||||
if (cache != null) {
|
|
||||||
return cache;
|
|
||||||
}
|
|
||||||
cache = new Map<string, Promise<any>>();
|
|
||||||
caches.set(obj, cache);
|
|
||||||
return cache;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function clearCaches() {
|
|
||||||
caches.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use as a Decorator on async functions, it will prevent multiple 'active' calls as the same time
|
|
||||||
*
|
|
||||||
* If a promise was returned from a previous call to this function, that hasn't yet resolved it will
|
|
||||||
* be returned, instead of calling the original function again
|
|
||||||
*
|
|
||||||
* Results are not cached, once the promise has returned, the next call will result in a fresh call
|
|
||||||
*
|
|
||||||
* Read more at https://github.com/bitwarden/jslib/pull/7
|
|
||||||
*/
|
|
||||||
export function sequentialize(cacheKey: (args: any[]) => string) {
|
|
||||||
return (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
|
|
||||||
const originalMethod: () => Promise<any> = descriptor.value;
|
|
||||||
|
|
||||||
return {
|
|
||||||
value: function (...args: any[]) {
|
|
||||||
const cache = getCache(this);
|
|
||||||
const argsCacheKey = cacheKey(args);
|
|
||||||
let response = cache.get(argsCacheKey);
|
|
||||||
if (response != null) {
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
const onFinally = () => {
|
|
||||||
cache.delete(argsCacheKey);
|
|
||||||
if (cache.size === 0) {
|
|
||||||
caches.delete(this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
response = originalMethod
|
|
||||||
.apply(this, args)
|
|
||||||
.then((val: any) => {
|
|
||||||
onFinally();
|
|
||||||
return val;
|
|
||||||
})
|
|
||||||
.catch((err: any) => {
|
|
||||||
onFinally();
|
|
||||||
throw err;
|
|
||||||
});
|
|
||||||
|
|
||||||
cache.set(argsCacheKey, response);
|
|
||||||
return response;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
import { sequentialize } from "./sequentialize";
|
|
||||||
import { throttle } from "./throttle";
|
import { throttle } from "./throttle";
|
||||||
|
|
||||||
describe("throttle decorator", () => {
|
describe("throttle decorator", () => {
|
||||||
@@ -51,17 +50,6 @@ describe("throttle decorator", () => {
|
|||||||
expect(foo.calls).toBe(10);
|
expect(foo.calls).toBe(10);
|
||||||
expect(foo2.calls).toBe(10);
|
expect(foo2.calls).toBe(10);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should work together with sequentialize", async () => {
|
|
||||||
const foo = new Foo();
|
|
||||||
const promises = [];
|
|
||||||
for (let i = 0; i < 10; i++) {
|
|
||||||
promises.push(foo.qux(Math.floor(i / 2) * 2));
|
|
||||||
}
|
|
||||||
await Promise.all(promises);
|
|
||||||
|
|
||||||
expect(foo.calls).toBe(5);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
class Foo {
|
class Foo {
|
||||||
@@ -94,7 +82,6 @@ class Foo {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@sequentialize((args) => "qux" + args[0])
|
|
||||||
@throttle(1, () => "qux")
|
@throttle(1, () => "qux")
|
||||||
qux(a: number) {
|
qux(a: number) {
|
||||||
this.calls++;
|
this.calls++;
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ import { FolderResponse } from "../../vault/models/response/folder.response";
|
|||||||
import { LogService } from "../abstractions/log.service";
|
import { LogService } from "../abstractions/log.service";
|
||||||
import { StateService } from "../abstractions/state.service";
|
import { StateService } from "../abstractions/state.service";
|
||||||
import { MessageSender } from "../messaging";
|
import { MessageSender } from "../messaging";
|
||||||
import { sequentialize } from "../misc/sequentialize";
|
|
||||||
import { StateProvider } from "../state";
|
import { StateProvider } from "../state";
|
||||||
|
|
||||||
import { CoreSyncService } from "./core-sync.service";
|
import { CoreSyncService } from "./core-sync.service";
|
||||||
@@ -103,7 +102,6 @@ export class DefaultSyncService extends CoreSyncService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@sequentialize(() => "fullSync")
|
|
||||||
override async fullSync(forceSync: boolean, allowThrowOnError = false): Promise<boolean> {
|
override async fullSync(forceSync: boolean, allowThrowOnError = false): Promise<boolean> {
|
||||||
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id)));
|
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id)));
|
||||||
this.syncStarted();
|
this.syncStarted();
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ import { View } from "../../models/view/view";
|
|||||||
import { ConfigService } from "../../platform/abstractions/config/config.service";
|
import { ConfigService } from "../../platform/abstractions/config/config.service";
|
||||||
import { I18nService } from "../../platform/abstractions/i18n.service";
|
import { I18nService } from "../../platform/abstractions/i18n.service";
|
||||||
import { StateService } from "../../platform/abstractions/state.service";
|
import { StateService } from "../../platform/abstractions/state.service";
|
||||||
import { sequentialize } from "../../platform/misc/sequentialize";
|
|
||||||
import { Utils } from "../../platform/misc/utils";
|
import { Utils } from "../../platform/misc/utils";
|
||||||
import Domain from "../../platform/models/domain/domain-base";
|
import Domain from "../../platform/models/domain/domain-base";
|
||||||
import { EncArrayBuffer } from "../../platform/models/domain/enc-array-buffer";
|
import { EncArrayBuffer } from "../../platform/models/domain/enc-array-buffer";
|
||||||
@@ -390,7 +389,6 @@ export class CipherService implements CipherServiceAbstraction {
|
|||||||
* cached, the cached ciphers are returned.
|
* cached, the cached ciphers are returned.
|
||||||
* @deprecated Use `cipherViews$` observable instead
|
* @deprecated Use `cipherViews$` observable instead
|
||||||
*/
|
*/
|
||||||
@sequentialize(() => "getAllDecrypted")
|
|
||||||
async getAllDecrypted(userId: UserId): Promise<CipherView[]> {
|
async getAllDecrypted(userId: UserId): Promise<CipherView[]> {
|
||||||
const decCiphers = await this.getDecryptedCiphers(userId);
|
const decCiphers = await this.getDecryptedCiphers(userId);
|
||||||
if (decCiphers != null && decCiphers.length !== 0) {
|
if (decCiphers != null && decCiphers.length !== 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user