From 3e6060d805bd6b5f88c311b86d429a4ca0c10a5d Mon Sep 17 00:00:00 2001 From: a179346 Date: Sat, 2 Mar 2024 20:35:23 +0800 Subject: [PATCH] Pause should not wait for retry delay --- package-lock.json | 4 ++-- package.json | 2 +- src/index.ts | 40 ++++++++++++++++++++++++++++++++++++---- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index e557092..5a01811 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "nextjs-chunk-upload-action", - "version": "6.0.0", + "version": "6.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "nextjs-chunk-upload-action", - "version": "6.0.0", + "version": "6.1.0", "license": "MIT", "devDependencies": { "@types/node": "^20.11.21", diff --git a/package.json b/package.json index ac6257a..542e78c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nextjs-chunk-upload-action", - "version": "6.0.0", + "version": "6.1.0", "description": "Uploading large files with chunking using server action in Next.js", "main": "dist/index.js", "scripts": { diff --git a/src/index.ts b/src/index.ts index 87fd0f5..6805a99 100644 --- a/src/index.ts +++ b/src/index.ts @@ -86,6 +86,7 @@ export class ChunkUploader { this._onPaused = options.onPaused; this._onAborted = options.onAborted; this._onStatusChange = options.onStatusChange; + this._statusChangedEventListeners = {}; if (this._onStatusChange) this._onStatusChange(undefined, this.status); } @@ -182,6 +183,8 @@ export class ChunkUploader { const oldValue = this._status; if (oldValue === value) return; this._status = value; + const listenerSet = this._statusChangedEventListeners[value]; + if (listenerSet) listenerSet.forEach(listener => listener()); if (this._onStatusChange) this._onStatusChange(oldValue, value); } protected _position: number; @@ -238,7 +241,7 @@ export class ChunkUploader { break; } catch (error) { if (this.status === 'pausing') return false; - if (retry < this._retryDelays.length) await wait(this._retryDelays[retry]); + if (retry < this._retryDelays.length) await this._waitForRetry(this._retryDelays[retry]); else { this.status = 'error'; this._error = error; @@ -307,8 +310,37 @@ export class ChunkUploader { throw new Error('onStatusChange must be a function'); } } -} -function wait(ms: number) { - return new Promise(resolve => setTimeout(resolve, ms)); + protected _waitForRetry(ms: number) { + return new Promise(resolve => { + let isResolved = false; + + const handleResolve = () => { + if (isResolved) return; + isResolved = true; + this._removeStatusChangedEventListener('pausing', handleResolve); + resolve(); + }; + + setTimeout(handleResolve, ms); + + this._addStatusChangedEventListener('pausing', handleResolve); + }); + } + + protected _statusChangedEventListeners: Partial void>>>; + + protected _addStatusChangedEventListener(status: ChunkUploaderStatus, listener: () => void) { + const listenerSet = this._statusChangedEventListeners[status] || new Set(); + if (!this._statusChangedEventListeners[status]) + this._statusChangedEventListeners[status] = listenerSet; + listenerSet.add(listener); + } + + protected _removeStatusChangedEventListener(status: ChunkUploaderStatus, listener: () => void) { + const listenerSet = this._statusChangedEventListeners[status] || new Set(); + if (!this._statusChangedEventListeners[status]) + this._statusChangedEventListeners[status] = listenerSet; + listenerSet.delete(listener); + } }