From 6d6fccf87f9e315bb3f029bd80ac24fd72f9f00a Mon Sep 17 00:00:00 2001 From: johniexu <281910378@qq.com> Date: Thu, 26 Jun 2025 11:25:50 +0800 Subject: [PATCH 1/5] =?UTF-8?q?fix:=20runWithDelayedLoading=20=E5=9C=A8?= =?UTF-8?q?=E5=BC=82=E6=AD=A5=E4=BB=BB=E5=8A=A1=E5=85=88=E4=BA=8E=20minLoa?= =?UTF-8?q?dingDuration=20=E5=AE=8C=E6=88=90=E6=97=B6=EF=BC=8C=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E7=9A=84=20Promise=20=E4=B8=8D=E4=BC=9A=E7=AD=89?= =?UTF-8?q?=E5=88=B0=E5=8A=A0=E8=BD=BD=E7=BB=93=E6=9D=9F=E6=89=8D=20Settle?= =?UTF-8?q?d?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common.test.ts | 26 ++++++++++++++++++++++++++ src/common.ts | 26 +++++++++++++++++++++----- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/common.test.ts b/src/common.test.ts index 5812b73..170c990 100644 --- a/src/common.test.ts +++ b/src/common.test.ts @@ -847,5 +847,31 @@ describe("runWithDelayedLoading", () => { await promise // No assertions needed, just verifying it doesn't throw }) + + it("should ensure returned promise not resolve before minLoadingDuration if async task finished before minLoadingDuration ", async () => { + vi.useFakeTimers() + + const mockTask = vi.fn(() => new Promise(resolve => setTimeout(() => resolve("result"), 300))) + const onLoading = vi.fn() + const onSettled = vi.fn() + + const promise = runWithDelayedLoading(mockTask, { + loadingDelay: 100, + onLoading, + onSettled, + minLoadingDuration: 500 + }) + + await vi.advanceTimersByTimeAsync(100) // Reach loadingDelay + expect(onLoading).toBeCalledTimes(1) + + await vi.advanceTimersByTimeAsync(200) // Task finishes (total 300ms) + expect(onSettled).not.toHaveBeenCalled() // TODO: 测试promise还没有Settled + + await vi.advanceTimersByTimeAsync(300) // minLoadingDuration reached (500ms total) + const result = await promise // TODO: 测试promise已经Settled + expect(result).toBe("result") + expect(onSettled).toBeCalledTimes(1) + }) }) diff --git a/src/common.ts b/src/common.ts index 2171c9a..99d5907 100644 --- a/src/common.ts +++ b/src/common.ts @@ -1054,11 +1054,13 @@ export async function runWithDelayedLoading(asyncTask: () => Promise }: IRunWithDelayedLoadingOptions = {}): Promise { let loading = false // 是否展示loading中 let settled = false // 异步任务是否完成 + // let resSettled = false // 返回的Promise是否已Settled + // let taskRes: T | Error | null = null // 异步任务返回的结果 // let taskStartTime: number | null = null // 异步任务开始时间 let loadingStartTime: number | null = null // 展示loading的开始时间 // let loadingDelayTimeout = false // 是否超时时间 - let resolve: ((d: Awaited | T) => void )| null = null + let resolve: ((d: Awaited | T) => void ) | null = null let reject: ((e: Error) => void) | null = null // taskStartTime = Date.now() @@ -1069,13 +1071,25 @@ export async function runWithDelayedLoading(asyncTask: () => Promise loadingStartTime = Date.now() onLoading?.() await runLoading() + } else { + // 忽略,返回的Promise已被处理 } }) const task = asyncTask().then((data) => { - resolve!(data) + if (!loading) { + resolve!(data) + // resSettled = true + } else { + // taskRes = data + } return data }, (e) => { - reject!(e) + if (!loading) { + reject!(e) + // resSettled = true + } else { + // taskRes = e + } return Promise.reject(e) }).finally(() => { settled = true @@ -1093,7 +1107,8 @@ export async function runWithDelayedLoading(asyncTask: () => Promise } loading = false onSettled?.(); - resolve!(res) + resolve!(res); + // resSettled = true } catch (e) { if (loadingStartTime !== null) { const elapsedTime = Date.now() - loadingStartTime @@ -1103,7 +1118,8 @@ export async function runWithDelayedLoading(asyncTask: () => Promise } loading = false onSettled?.(); - reject!(e as Error) + reject!(e as Error); + // resSettled = true } } From a85c0ada2c04b6c97ad0ca72569a83cdbfc1657d Mon Sep 17 00:00:00 2001 From: johniexu <281910378@qq.com> Date: Thu, 26 Jun 2025 15:07:22 +0800 Subject: [PATCH 2/5] fix: Update common.test.ts --- src/common.test.ts | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/common.test.ts b/src/common.test.ts index 170c990..1bbfc67 100644 --- a/src/common.test.ts +++ b/src/common.test.ts @@ -807,12 +807,22 @@ describe("runWithDelayedLoading", () => { expect(onLoading).toBeCalledTimes(1) await vi.advanceTimersByTimeAsync(200) // Task finishes (total 300ms) - const result = await promise - expect(result).toBe("result") + const isSettled1 = await Promise.race([ + promise.then(() => true, () => true), + Promise.resolve(false) + ]) + expect(isSettled1).toBe(false) // promise should not settled - // Should still wait additional 400ms to meet minLoadingDuration (500ms total) - await vi.advanceTimersByTimeAsync(400) + // Should still wait additional 300ms to meet minLoadingDuration (500ms total) + await vi.advanceTimersByTimeAsync(300) expect(onSettled).toBeCalledTimes(1) + const isSettled2 = await Promise.race([ + promise.then(() => true, () => true), + Promise.resolve(false) + ]) + const result = await promise + expect(result).toBe("result") + expect(isSettled2).toBe(true) // promise should be settled }) // this will cause vitest throw error skip temporally @@ -866,11 +876,21 @@ describe("runWithDelayedLoading", () => { expect(onLoading).toBeCalledTimes(1) await vi.advanceTimersByTimeAsync(200) // Task finishes (total 300ms) - expect(onSettled).not.toHaveBeenCalled() // TODO: 测试promise还没有Settled + const isSettled1 = await Promise.race([ + promise.then(() => true, () => true), + Promise.resolve(false) + ]) + expect(isSettled1).toBe(false) // promise should not settled + expect(onSettled).not.toHaveBeenCalled() await vi.advanceTimersByTimeAsync(300) // minLoadingDuration reached (500ms total) - const result = await promise // TODO: 测试promise已经Settled + const isSettled2 = await Promise.race([ + promise.then(() => true, () => true), + Promise.resolve(false) + ]) + const result = await promise expect(result).toBe("result") + expect(isSettled2).toBe(true) // promise should be settled expect(onSettled).toBeCalledTimes(1) }) }) From 359b36b4c7941ca7b89025bd4573c8fbad063623 Mon Sep 17 00:00:00 2001 From: johniexu <281910378@qq.com> Date: Thu, 26 Jun 2025 16:55:14 +0800 Subject: [PATCH 3/5] chore: improve test logic --- src/common.test.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/common.test.ts b/src/common.test.ts index 1bbfc67..ef6fc8c 100644 --- a/src/common.test.ts +++ b/src/common.test.ts @@ -805,6 +805,7 @@ describe("runWithDelayedLoading", () => { await vi.advanceTimersByTimeAsync(100) // Reach loadingDelay expect(onLoading).toBeCalledTimes(1) + expect(onSettled).not.toHaveBeenCalled() await vi.advanceTimersByTimeAsync(200) // Task finishes (total 300ms) const isSettled1 = await Promise.race([ @@ -812,6 +813,7 @@ describe("runWithDelayedLoading", () => { Promise.resolve(false) ]) expect(isSettled1).toBe(false) // promise should not settled + expect(onSettled).not.toHaveBeenCalled() // Should still wait additional 300ms to meet minLoadingDuration (500ms total) await vi.advanceTimersByTimeAsync(300) @@ -874,6 +876,7 @@ describe("runWithDelayedLoading", () => { await vi.advanceTimersByTimeAsync(100) // Reach loadingDelay expect(onLoading).toBeCalledTimes(1) + expect(onSettled).not.toHaveBeenCalled() await vi.advanceTimersByTimeAsync(200) // Task finishes (total 300ms) const isSettled1 = await Promise.race([ From 364ba5f9ba74ef9ae63b7e2cad9f2c9f132fda83 Mon Sep 17 00:00:00 2001 From: JohnieXu <281910378@qq.com> Date: Thu, 26 Jun 2025 18:11:22 +0800 Subject: [PATCH 4/5] =?UTF-8?q?chore:=20=E6=B8=85=E7=90=86=E6=97=A0?= =?UTF-8?q?=E7=94=A8=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/common.ts b/src/common.ts index 99d5907..5fe565c 100644 --- a/src/common.ts +++ b/src/common.ts @@ -1055,7 +1055,6 @@ export async function runWithDelayedLoading(asyncTask: () => Promise let loading = false // 是否展示loading中 let settled = false // 异步任务是否完成 // let resSettled = false // 返回的Promise是否已Settled - // let taskRes: T | Error | null = null // 异步任务返回的结果 // let taskStartTime: number | null = null // 异步任务开始时间 let loadingStartTime: number | null = null // 展示loading的开始时间 // let loadingDelayTimeout = false // 是否超时时间 @@ -1080,7 +1079,6 @@ export async function runWithDelayedLoading(asyncTask: () => Promise resolve!(data) // resSettled = true } else { - // taskRes = data } return data }, (e) => { @@ -1088,7 +1086,6 @@ export async function runWithDelayedLoading(asyncTask: () => Promise reject!(e) // resSettled = true } else { - // taskRes = e } return Promise.reject(e) }).finally(() => { From fdb1a864a127b29bf8bf8ba4962fb0239b5bdb53 Mon Sep 17 00:00:00 2001 From: JohnieXu <281910378@qq.com> Date: Sat, 28 Jun 2025 11:02:19 +0800 Subject: [PATCH 5/5] chore: improve test logic --- src/common.test.ts | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/common.test.ts b/src/common.test.ts index ef6fc8c..6a05a65 100644 --- a/src/common.test.ts +++ b/src/common.test.ts @@ -736,6 +736,9 @@ describe('runWithTimeout', () => { }) describe("runWithDelayedLoading", () => { + afterEach(() => { + vi.useRealTimers() + }) it("should resolve immediately after delayed if task finishes before loadingDelay", async () => { vi.useFakeTimers() @@ -750,14 +753,9 @@ describe("runWithDelayedLoading", () => { }) await vi.advanceTimersByTimeAsync(50) // Task finishes before loadingDelay - // mockTask.mock.results[0].value.then(() => {}) // Resolve the task - - // const result = await promise - // expect(result).toBe("result") expect(onLoading).not.toHaveBeenCalled() expect(onSettled).not.toHaveBeenCalled() - await vi.advanceTimersByTimeAsync(50) // Task finishes immediately after loadingDelay const result = await promise expect(result).toBe("result") expect(onLoading).not.toHaveBeenCalled() @@ -808,11 +806,12 @@ describe("runWithDelayedLoading", () => { expect(onSettled).not.toHaveBeenCalled() await vi.advanceTimersByTimeAsync(200) // Task finishes (total 300ms) + const isSettled1 = await Promise.race([ promise.then(() => true, () => true), - Promise.resolve(false) + Promise.resolve(false).then(r => r), ]) - expect(isSettled1).toBe(false) // promise should not settled + expect(isSettled1).toBe(false) // promise should not settle expect(onSettled).not.toHaveBeenCalled() // Should still wait additional 300ms to meet minLoadingDuration (500ms total) @@ -820,7 +819,7 @@ describe("runWithDelayedLoading", () => { expect(onSettled).toBeCalledTimes(1) const isSettled2 = await Promise.race([ promise.then(() => true, () => true), - Promise.resolve(false) + Promise.resolve(false).then(r => r), ]) const result = await promise expect(result).toBe("result") @@ -881,15 +880,15 @@ describe("runWithDelayedLoading", () => { await vi.advanceTimersByTimeAsync(200) // Task finishes (total 300ms) const isSettled1 = await Promise.race([ promise.then(() => true, () => true), - Promise.resolve(false) + Promise.resolve(false).then(r => r) ]) - expect(isSettled1).toBe(false) // promise should not settled + expect(isSettled1).toBe(false) // promise should not settle expect(onSettled).not.toHaveBeenCalled() await vi.advanceTimersByTimeAsync(300) // minLoadingDuration reached (500ms total) const isSettled2 = await Promise.race([ promise.then(() => true, () => true), - Promise.resolve(false) + Promise.resolve(false).then(r => r) ]) const result = await promise expect(result).toBe("result")