Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions src/util/jsonp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,23 @@ export function jsonp<T>(

// リソース解放用の関数を定義
// スクリプトタグの削除、コールバック関数のクリーンアップ、タイマーのクリアを行う
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);
Expand All @@ -94,7 +103,7 @@ export function jsonp<T>(
const timer =
timeout > 0
? setTimeout(() => {
cleanup();
cleanup(true);
reject(new Error("Timeout"));
}, timeout)
: undefined;
Expand Down
14 changes: 14 additions & 0 deletions test/util/jsonp.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand Down Expand Up @@ -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 () => {
Expand All @@ -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 () => {
Expand Down
Loading