diff --git a/src/util/jsonp.ts b/src/util/jsonp.ts index c76b824..d67c794 100644 --- a/src/util/jsonp.ts +++ b/src/util/jsonp.ts @@ -75,14 +75,23 @@ export function jsonp( // リソース解放用の関数を定義 // スクリプトタグの削除、コールバック関数のクリーンアップ、タイマーのクリアを行う - const cleanup = function () { + const cleanup = function (isTimeout = false) { // Remove the script tag. if (script && script.parentNode) { script.parentNode.removeChild(script); } - // コールバック関数を空の関数に置き換えてメモリリークを防止 - window[id] = noop; + if (isTimeout) { + // タイムアウト時は遅延レスポンスによるコンソールエラーを避けるためにnoopを代入 + window[id] = noop; + } else { + // 成功時は完全に削除してメモリリークを防止 + try { + delete window[id]; + } catch { + window[id] = undefined as any; + } + } if (timer) { clearTimeout(timer); @@ -94,7 +103,7 @@ export function jsonp( const timer = timeout > 0 ? setTimeout(() => { - cleanup(); + cleanup(true); reject(new Error("Timeout")); }, timeout) : undefined; diff --git a/test/util/jsonp.test.ts b/test/util/jsonp.test.ts index b30ed57..46c9cbd 100644 --- a/test/util/jsonp.test.ts +++ b/test/util/jsonp.test.ts @@ -130,6 +130,10 @@ describe('jsonp', () => { const result = await jsonpPromise; expect(result).toEqual(mockData); expect(mockParentNode.insertBefore).toHaveBeenCalledWith(mockScript, expect.anything()); + + // Check if callback is cleaned up (deleted on success) + expect(window[callbackName]).toBeUndefined(); + expect(callbackName in window).toBe(false); }); test('should apply custom options', async () => { @@ -161,6 +165,10 @@ describe('jsonp', () => { const result = await jsonpPromise; expect(result).toEqual(mockData); + + // Check if callback is cleaned up (deleted on success) + expect(window[callbackName]).toBeUndefined(); + expect(callbackName in window).toBe(false); }); test('should timeout and reject the promise', async () => { @@ -173,6 +181,12 @@ describe('jsonp', () => { vi.advanceTimersByTime(1001); await expect(promise).rejects.toThrow('Timeout'); + + // Check if callback is replaced by noop on timeout (not deleted) + const timeoutId = Object.keys(window).find(key => key.startsWith('__jp') && typeof window[key] === 'function'); + expect(timeoutId).toBeDefined(); + expect(typeof window[timeoutId!]).toBe('function'); + expect(timeoutId! in window).toBe(true); }); test('should use document.head if no script tags exist', async () => {