diff --git a/extension/chrome/settings/inbox/inbox-modules/inbox-list-threads-module.ts b/extension/chrome/settings/inbox/inbox-modules/inbox-list-threads-module.ts index 78dc5cd9ddb..5906f9369ac 100644 --- a/extension/chrome/settings/inbox/inbox-modules/inbox-list-threads-module.ts +++ b/extension/chrome/settings/inbox/inbox-modules/inbox-list-threads-module.ts @@ -7,7 +7,7 @@ import { Catch } from '../../../../js/common/platform/catch.js'; import { GmailParser } from '../../../../js/common/api/email-provider/gmail/gmail-parser.js'; import { InboxView } from '../inbox.js'; import { Lang } from '../../../../js/common/lang.js'; -import { Str } from '../../../../js/common/core/common.js'; +import { Str, promiseAllWithLimit } from '../../../../js/common/core/common.js'; import { Ui } from '../../../../js/common/browser/ui.js'; import { ViewModule } from '../../../../js/common/view-module.js'; import { Xss } from '../../../../js/common/platform/xss.js'; @@ -18,7 +18,10 @@ export class InboxListThreadsModule extends ViewModule { try { const { threads } = await this.view.gmail.threadList(labelId); if (threads?.length) { - await Promise.all(threads.map(t => this.renderInboxItem(t.id))); + await promiseAllWithLimit( + threads.map(t => () => this.renderInboxItem(t.id)), + 3 + ); } else { Xss.sanitizeRender('.threads', `

No encrypted messages in ${Xss.escape(labelId)} yet. ${Ui.retryLink()}

`); } @@ -39,7 +42,7 @@ export class InboxListThreadsModule extends ViewModule { } }; - private renderInboxItem = async (threadId: string) => { + private renderInboxItem = async (threadId: string): Promise => { this.inboxThreadItemAdd(threadId); const threadItem = $('.threads #' + this.threadListItemId(threadId)); try { diff --git a/extension/js/common/api/email-provider/gmail/gmail.ts b/extension/js/common/api/email-provider/gmail/gmail.ts index 7d70241f58b..2060e8464a2 100644 --- a/extension/js/common/api/email-provider/gmail/gmail.ts +++ b/extension/js/common/api/email-provider/gmail/gmail.ts @@ -4,7 +4,7 @@ import { AddrParserResult, BrowserWindow } from '../../../browser/browser-window.js'; import { ChunkedCb, ProgressCb, EmailProviderContact } from '../../shared/api.js'; -import { Dict, Str, Value } from '../../../core/common.js'; +import { Dict, Str, Value, promiseAllWithLimit } from '../../../core/common.js'; import { EmailProviderApi, EmailProviderInterface, Backups } from '../email-provider-api.js'; import { GMAIL_GOOGLE_API_HOST, gmailBackupSearchQuery } from '../../../core/const.js'; import { GmailParser, GmailRes } from './gmail-parser.js'; @@ -136,7 +136,10 @@ export class Gmail extends EmailProviderApi implements EmailProviderInterface { }; public msgsGet = async (msgIds: string[], format: GmailResponseFormat): Promise => { - return await Promise.all(msgIds.map(id => this.msgGet(id, format))); + return await promiseAllWithLimit( + msgIds.map(id => () => this.msgGet(id, format)), + 10 + ); }; public labelsGet = async (): Promise => { diff --git a/extension/js/common/core/common.ts b/extension/js/common/core/common.ts index fab1cbb39a8..2aa88a50e54 100644 --- a/extension/js/common/core/common.ts +++ b/extension/js/common/core/common.ts @@ -517,3 +517,45 @@ export const checkValidURL = (url: string): boolean => { const pattern = /(http|https):\/\/([a-z0-9-]+((\.[a-z0-9-]+)+)?)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@\-\/]))?/; return pattern.test(url); }; + +// Type definition for a function that returns a promise +type PromiseFunction = () => Promise; + +// promiseAllWithLimit as a const holding an arrow function +export const promiseAllWithLimit = (promiseFunctions: PromiseFunction[], limit: number): Promise => { + return new Promise((resolve, reject) => { + let resolvedCount = 0; + let count = 0; + const results: T[] = new Array(promiseFunctions.length); + const len = promiseFunctions.length; + + // Declare `next` as a const arrow function + const next = (promiseFunc: PromiseFunction, index: number) => { + promiseFunc() + .then(result => { + results[index] = result; + resolvedCount++; + if (promiseFunctions.length) { + const nextPromiseFunc = promiseFunctions.shift(); + if (nextPromiseFunc) { + next(nextPromiseFunc, count); + count++; + } + } else if (resolvedCount === len) { + resolve(results); + } + }) + .catch(error => { + reject(error); + }); + }; + + while (count < limit && promiseFunctions.length) { + const nextPromiseFunc = promiseFunctions.shift(); + if (nextPromiseFunc) { + next(nextPromiseFunc, count); + count++; + } + } + }); +};