@yh-ui/request 1.0.52 → 1.0.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/http-cache.cjs +4 -0
- package/dist/http-cache.mjs +4 -0
- package/dist/request.cjs +8 -2
- package/dist/request.mjs +8 -2
- package/dist/useLoadMore.cjs +8 -10
- package/dist/useLoadMore.mjs +8 -10
- package/dist/usePagination.cjs +35 -7
- package/dist/usePagination.mjs +35 -7
- package/dist/useQueue.cjs +33 -10
- package/dist/useQueue.d.ts +6 -2
- package/dist/useQueue.mjs +31 -10
- package/dist/useRequest.cjs +57 -18
- package/dist/useRequest.d.ts +6 -2
- package/dist/useRequest.mjs +73 -21
- package/dist/websocket.cjs +40 -15
- package/dist/websocket.d.ts +4 -0
- package/dist/websocket.mjs +32 -14
- package/package.json +2 -2
package/dist/http-cache.cjs
CHANGED
|
@@ -49,6 +49,9 @@ class HttpCache {
|
|
|
49
49
|
if (!entry) return void 0;
|
|
50
50
|
const now = Date.now();
|
|
51
51
|
if (entry.expireTime && now > entry.expireTime) {
|
|
52
|
+
if (this.options.staleWhileRevalidate && now <= entry.expireTime + this.options.staleTime) {
|
|
53
|
+
return entry;
|
|
54
|
+
}
|
|
52
55
|
this.cache.delete(key);
|
|
53
56
|
return void 0;
|
|
54
57
|
}
|
|
@@ -193,6 +196,7 @@ function createHttpCacheInterceptor(options = {}) {
|
|
|
193
196
|
const key = `${response.config.method}:${response.config.fullPath || response.config.url}`;
|
|
194
197
|
const entry = cache.get(key);
|
|
195
198
|
if (entry) {
|
|
199
|
+
cache.set(key, entry.data, response.response);
|
|
196
200
|
return {
|
|
197
201
|
...response,
|
|
198
202
|
data: entry.data
|
package/dist/http-cache.mjs
CHANGED
|
@@ -35,6 +35,9 @@ export class HttpCache {
|
|
|
35
35
|
if (!entry) return void 0;
|
|
36
36
|
const now = Date.now();
|
|
37
37
|
if (entry.expireTime && now > entry.expireTime) {
|
|
38
|
+
if (this.options.staleWhileRevalidate && now <= entry.expireTime + this.options.staleTime) {
|
|
39
|
+
return entry;
|
|
40
|
+
}
|
|
38
41
|
this.cache.delete(key);
|
|
39
42
|
return void 0;
|
|
40
43
|
}
|
|
@@ -175,6 +178,7 @@ export function createHttpCacheInterceptor(options = {}) {
|
|
|
175
178
|
const key = `${response.config.method}:${response.config.fullPath || response.config.url}`;
|
|
176
179
|
const entry = cache.get(key);
|
|
177
180
|
if (entry) {
|
|
181
|
+
cache.set(key, entry.data, response.response);
|
|
178
182
|
return {
|
|
179
183
|
...response,
|
|
180
184
|
data: entry.data
|
package/dist/request.cjs
CHANGED
|
@@ -71,8 +71,14 @@ function createRequestError(error, config, response) {
|
|
|
71
71
|
requestError.isNetworkError = true;
|
|
72
72
|
requestError.code = "NETWORK_ERROR";
|
|
73
73
|
} else if (config?.signal?.aborted) {
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
const isTimeout = err.message.toLowerCase().includes("timeout") || err.name === "TimeoutError" || (config.signal.reason instanceof Error ? config.signal.reason.message.toLowerCase().includes("timeout") : String(config.signal.reason).toLowerCase().includes("timeout"));
|
|
75
|
+
if (isTimeout) {
|
|
76
|
+
requestError.isTimeout = true;
|
|
77
|
+
requestError.code = "TIMEOUT";
|
|
78
|
+
} else {
|
|
79
|
+
requestError.isCanceled = true;
|
|
80
|
+
requestError.code = "CANCELED";
|
|
81
|
+
}
|
|
76
82
|
} else if (response) {
|
|
77
83
|
requestError.code = `HTTP_${response.status}`;
|
|
78
84
|
}
|
package/dist/request.mjs
CHANGED
|
@@ -49,8 +49,14 @@ export function createRequestError(error, config, response) {
|
|
|
49
49
|
requestError.isNetworkError = true;
|
|
50
50
|
requestError.code = "NETWORK_ERROR";
|
|
51
51
|
} else if (config?.signal?.aborted) {
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
const isTimeout = err.message.toLowerCase().includes("timeout") || err.name === "TimeoutError" || (config.signal.reason instanceof Error ? config.signal.reason.message.toLowerCase().includes("timeout") : String(config.signal.reason).toLowerCase().includes("timeout"));
|
|
53
|
+
if (isTimeout) {
|
|
54
|
+
requestError.isTimeout = true;
|
|
55
|
+
requestError.code = "TIMEOUT";
|
|
56
|
+
} else {
|
|
57
|
+
requestError.isCanceled = true;
|
|
58
|
+
requestError.code = "CANCELED";
|
|
59
|
+
}
|
|
54
60
|
} else if (response) {
|
|
55
61
|
requestError.code = `HTTP_${response.status}`;
|
|
56
62
|
}
|
package/dist/useLoadMore.cjs
CHANGED
|
@@ -38,7 +38,7 @@ function useLoadMore(service, options = {}) {
|
|
|
38
38
|
return isLoadMore && !noMore.value && !loadingMore.value;
|
|
39
39
|
});
|
|
40
40
|
const loadService = loadMoreService || service;
|
|
41
|
-
const loadData = async (isRefresh = false) => {
|
|
41
|
+
const loadData = async (requestedPage, isRefresh = false) => {
|
|
42
42
|
if (loading.value || loadingMore.value) return;
|
|
43
43
|
const isLoadMoreOp = !isRefresh;
|
|
44
44
|
loading.value = isLoadMoreOp ? false : true;
|
|
@@ -47,7 +47,7 @@ function useLoadMore(service, options = {}) {
|
|
|
47
47
|
error.value = void 0;
|
|
48
48
|
try {
|
|
49
49
|
const extraParams = params.value.slice(2);
|
|
50
|
-
const response = await loadService(
|
|
50
|
+
const response = await loadService(requestedPage, pageSize.value, ...extraParams);
|
|
51
51
|
const pageData = response.data;
|
|
52
52
|
if (pageData && typeof pageData === "object") {
|
|
53
53
|
const paginatedData = pageData;
|
|
@@ -55,7 +55,6 @@ function useLoadMore(service, options = {}) {
|
|
|
55
55
|
}
|
|
56
56
|
if (isRefresh) {
|
|
57
57
|
data.value = pageData;
|
|
58
|
-
current.value = initialPage + 1;
|
|
59
58
|
} else {
|
|
60
59
|
const oldData = data.value;
|
|
61
60
|
if (Array.isArray(oldData) && Array.isArray(pageData)) {
|
|
@@ -63,8 +62,8 @@ function useLoadMore(service, options = {}) {
|
|
|
63
62
|
} else {
|
|
64
63
|
data.value = pageData;
|
|
65
64
|
}
|
|
66
|
-
current.value++;
|
|
67
65
|
}
|
|
66
|
+
current.value = requestedPage;
|
|
68
67
|
onSuccess?.(pageData, params.value);
|
|
69
68
|
} catch (err) {
|
|
70
69
|
error.value = err;
|
|
@@ -78,19 +77,18 @@ function useLoadMore(service, options = {}) {
|
|
|
78
77
|
};
|
|
79
78
|
const loadMore = async () => {
|
|
80
79
|
if (noMore.value || loadingMore.value) return;
|
|
81
|
-
await loadData(false);
|
|
80
|
+
await loadData(current.value + 1, false);
|
|
82
81
|
};
|
|
83
82
|
const reload = async () => {
|
|
84
|
-
|
|
85
|
-
await loadData(true);
|
|
83
|
+
await loadData(initialPage, true);
|
|
86
84
|
};
|
|
87
85
|
const refresh = async () => {
|
|
88
86
|
await reload();
|
|
89
87
|
};
|
|
90
88
|
const pagination = {
|
|
91
89
|
loadPage: async page => {
|
|
92
|
-
|
|
93
|
-
await loadData(true);
|
|
90
|
+
if (page < 1 || totalPages.value > 0 && page > totalPages.value) return;
|
|
91
|
+
await loadData(page, true);
|
|
94
92
|
},
|
|
95
93
|
nextPage: loadMore,
|
|
96
94
|
prevPage: async () => {
|
|
@@ -112,7 +110,7 @@ function useLoadMore(service, options = {}) {
|
|
|
112
110
|
};
|
|
113
111
|
if (!manual) {
|
|
114
112
|
(0, _vue.onMounted)(() => {
|
|
115
|
-
loadData();
|
|
113
|
+
loadData(current.value, false);
|
|
116
114
|
});
|
|
117
115
|
}
|
|
118
116
|
return {
|
package/dist/useLoadMore.mjs
CHANGED
|
@@ -32,7 +32,7 @@ export function useLoadMore(service, options = {}) {
|
|
|
32
32
|
return isLoadMore && !noMore.value && !loadingMore.value;
|
|
33
33
|
});
|
|
34
34
|
const loadService = loadMoreService || service;
|
|
35
|
-
const loadData = async (isRefresh = false) => {
|
|
35
|
+
const loadData = async (requestedPage, isRefresh = false) => {
|
|
36
36
|
if (loading.value || loadingMore.value) return;
|
|
37
37
|
const isLoadMoreOp = !isRefresh;
|
|
38
38
|
loading.value = isLoadMoreOp ? false : true;
|
|
@@ -41,7 +41,7 @@ export function useLoadMore(service, options = {}) {
|
|
|
41
41
|
error.value = void 0;
|
|
42
42
|
try {
|
|
43
43
|
const extraParams = params.value.slice(2);
|
|
44
|
-
const response = await loadService(
|
|
44
|
+
const response = await loadService(requestedPage, pageSize.value, ...extraParams);
|
|
45
45
|
const pageData = response.data;
|
|
46
46
|
if (pageData && typeof pageData === "object") {
|
|
47
47
|
const paginatedData = pageData;
|
|
@@ -53,7 +53,6 @@ export function useLoadMore(service, options = {}) {
|
|
|
53
53
|
}
|
|
54
54
|
if (isRefresh) {
|
|
55
55
|
data.value = pageData;
|
|
56
|
-
current.value = initialPage + 1;
|
|
57
56
|
} else {
|
|
58
57
|
const oldData = data.value;
|
|
59
58
|
if (Array.isArray(oldData) && Array.isArray(pageData)) {
|
|
@@ -61,8 +60,8 @@ export function useLoadMore(service, options = {}) {
|
|
|
61
60
|
} else {
|
|
62
61
|
data.value = pageData;
|
|
63
62
|
}
|
|
64
|
-
current.value++;
|
|
65
63
|
}
|
|
64
|
+
current.value = requestedPage;
|
|
66
65
|
onSuccess?.(pageData, params.value);
|
|
67
66
|
} catch (err) {
|
|
68
67
|
error.value = err;
|
|
@@ -76,19 +75,18 @@ export function useLoadMore(service, options = {}) {
|
|
|
76
75
|
};
|
|
77
76
|
const loadMore = async () => {
|
|
78
77
|
if (noMore.value || loadingMore.value) return;
|
|
79
|
-
await loadData(false);
|
|
78
|
+
await loadData(current.value + 1, false);
|
|
80
79
|
};
|
|
81
80
|
const reload = async () => {
|
|
82
|
-
|
|
83
|
-
await loadData(true);
|
|
81
|
+
await loadData(initialPage, true);
|
|
84
82
|
};
|
|
85
83
|
const refresh = async () => {
|
|
86
84
|
await reload();
|
|
87
85
|
};
|
|
88
86
|
const pagination = {
|
|
89
87
|
loadPage: async (page) => {
|
|
90
|
-
|
|
91
|
-
await loadData(true);
|
|
88
|
+
if (page < 1 || totalPages.value > 0 && page > totalPages.value) return;
|
|
89
|
+
await loadData(page, true);
|
|
92
90
|
},
|
|
93
91
|
nextPage: loadMore,
|
|
94
92
|
prevPage: async () => {
|
|
@@ -110,7 +108,7 @@ export function useLoadMore(service, options = {}) {
|
|
|
110
108
|
};
|
|
111
109
|
if (!manual) {
|
|
112
110
|
onMounted(() => {
|
|
113
|
-
loadData();
|
|
111
|
+
loadData(current.value, false);
|
|
114
112
|
});
|
|
115
113
|
}
|
|
116
114
|
return {
|
package/dist/usePagination.cjs
CHANGED
|
@@ -69,8 +69,16 @@ function usePagination(service, options = {}) {
|
|
|
69
69
|
};
|
|
70
70
|
const loadPage = async page => {
|
|
71
71
|
if (page < 1 || totalPages.value > 0 && page > totalPages.value) return;
|
|
72
|
+
if (current.value === page) {
|
|
73
|
+
if (manual) {
|
|
74
|
+
await loadData();
|
|
75
|
+
}
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
72
78
|
current.value = page;
|
|
73
|
-
|
|
79
|
+
if (manual) {
|
|
80
|
+
await loadData();
|
|
81
|
+
}
|
|
74
82
|
};
|
|
75
83
|
const nextPage = async () => {
|
|
76
84
|
if (noMore.value) return;
|
|
@@ -86,14 +94,31 @@ function usePagination(service, options = {}) {
|
|
|
86
94
|
await loadPage(totalPages.value);
|
|
87
95
|
};
|
|
88
96
|
const refresh = async () => {
|
|
89
|
-
current.value = 1;
|
|
90
97
|
refreshing.value = true;
|
|
91
|
-
|
|
98
|
+
if (current.value === 1) {
|
|
99
|
+
await loadData();
|
|
100
|
+
} else {
|
|
101
|
+
current.value = 1;
|
|
102
|
+
if (manual) {
|
|
103
|
+
await loadData();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
92
106
|
};
|
|
93
107
|
const setPageSize = size => {
|
|
108
|
+
if (pageSize.value === size) {
|
|
109
|
+
if (manual) {
|
|
110
|
+
loadData();
|
|
111
|
+
}
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
94
114
|
pageSize.value = size;
|
|
95
|
-
if (
|
|
96
|
-
|
|
115
|
+
if (manual) {
|
|
116
|
+
if (current.value === 1) {
|
|
117
|
+
loadData();
|
|
118
|
+
} else {
|
|
119
|
+
current.value = 1;
|
|
120
|
+
loadData();
|
|
121
|
+
}
|
|
97
122
|
}
|
|
98
123
|
};
|
|
99
124
|
const setTotal = newTotal => {
|
|
@@ -101,8 +126,11 @@ function usePagination(service, options = {}) {
|
|
|
101
126
|
};
|
|
102
127
|
(0, _vue.watch)(pageSize, () => {
|
|
103
128
|
if (!manual) {
|
|
104
|
-
current.value
|
|
105
|
-
|
|
129
|
+
if (current.value === 1) {
|
|
130
|
+
loadData();
|
|
131
|
+
} else {
|
|
132
|
+
current.value = 1;
|
|
133
|
+
}
|
|
106
134
|
}
|
|
107
135
|
});
|
|
108
136
|
(0, _vue.watch)(current, () => {
|
package/dist/usePagination.mjs
CHANGED
|
@@ -60,8 +60,16 @@ export function usePagination(service, options = {}) {
|
|
|
60
60
|
};
|
|
61
61
|
const loadPage = async (page) => {
|
|
62
62
|
if (page < 1 || totalPages.value > 0 && page > totalPages.value) return;
|
|
63
|
+
if (current.value === page) {
|
|
64
|
+
if (manual) {
|
|
65
|
+
await loadData();
|
|
66
|
+
}
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
63
69
|
current.value = page;
|
|
64
|
-
|
|
70
|
+
if (manual) {
|
|
71
|
+
await loadData();
|
|
72
|
+
}
|
|
65
73
|
};
|
|
66
74
|
const nextPage = async () => {
|
|
67
75
|
if (noMore.value) return;
|
|
@@ -77,14 +85,31 @@ export function usePagination(service, options = {}) {
|
|
|
77
85
|
await loadPage(totalPages.value);
|
|
78
86
|
};
|
|
79
87
|
const refresh = async () => {
|
|
80
|
-
current.value = 1;
|
|
81
88
|
refreshing.value = true;
|
|
82
|
-
|
|
89
|
+
if (current.value === 1) {
|
|
90
|
+
await loadData();
|
|
91
|
+
} else {
|
|
92
|
+
current.value = 1;
|
|
93
|
+
if (manual) {
|
|
94
|
+
await loadData();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
83
97
|
};
|
|
84
98
|
const setPageSize = (size) => {
|
|
99
|
+
if (pageSize.value === size) {
|
|
100
|
+
if (manual) {
|
|
101
|
+
loadData();
|
|
102
|
+
}
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
85
105
|
pageSize.value = size;
|
|
86
|
-
if (
|
|
87
|
-
|
|
106
|
+
if (manual) {
|
|
107
|
+
if (current.value === 1) {
|
|
108
|
+
loadData();
|
|
109
|
+
} else {
|
|
110
|
+
current.value = 1;
|
|
111
|
+
loadData();
|
|
112
|
+
}
|
|
88
113
|
}
|
|
89
114
|
};
|
|
90
115
|
const setTotal = (newTotal) => {
|
|
@@ -92,8 +117,11 @@ export function usePagination(service, options = {}) {
|
|
|
92
117
|
};
|
|
93
118
|
watch(pageSize, () => {
|
|
94
119
|
if (!manual) {
|
|
95
|
-
current.value
|
|
96
|
-
|
|
120
|
+
if (current.value === 1) {
|
|
121
|
+
loadData();
|
|
122
|
+
} else {
|
|
123
|
+
current.value = 1;
|
|
124
|
+
}
|
|
97
125
|
}
|
|
98
126
|
});
|
|
99
127
|
watch(current, () => {
|
package/dist/useQueue.cjs
CHANGED
|
@@ -20,6 +20,7 @@ function useQueue(options = {}) {
|
|
|
20
20
|
} = options;
|
|
21
21
|
const taskList = (0, _vue.reactive)([]);
|
|
22
22
|
const taskMap = /* @__PURE__ */new Map();
|
|
23
|
+
const abortControllers = /* @__PURE__ */new Map();
|
|
23
24
|
const isRunning = (0, _vue.ref)(false);
|
|
24
25
|
const isPaused = (0, _vue.ref)(false);
|
|
25
26
|
const currentTaskIds = /* @__PURE__ */new Set();
|
|
@@ -44,23 +45,34 @@ function useQueue(options = {}) {
|
|
|
44
45
|
const totalCount = (0, _vue.computed)(() => tasks.value.length);
|
|
45
46
|
const executeTask = async task => {
|
|
46
47
|
if (task.status === "canceled" || task.status === "running") return;
|
|
48
|
+
const controller = new AbortController();
|
|
49
|
+
abortControllers.set(task.id, controller);
|
|
47
50
|
task.status = "running";
|
|
48
51
|
task.startTime = Date.now();
|
|
49
52
|
currentTaskIds.add(task.id);
|
|
50
53
|
triggerUpdate();
|
|
51
54
|
try {
|
|
52
55
|
if (task.delay && task.delay > 0) {
|
|
53
|
-
await new Promise(
|
|
56
|
+
await new Promise((resolve, reject) => {
|
|
57
|
+
const timeoutId = setTimeout(resolve, task.delay);
|
|
58
|
+
controller.signal.addEventListener("abort", () => {
|
|
59
|
+
clearTimeout(timeoutId);
|
|
60
|
+
reject(new Error("Canceled"));
|
|
61
|
+
});
|
|
62
|
+
});
|
|
54
63
|
}
|
|
55
|
-
if (task.status === "canceled") return;
|
|
56
|
-
const result = await task.task(
|
|
57
|
-
|
|
64
|
+
if (task.status === "canceled" || controller.signal.aborted) return;
|
|
65
|
+
const result = await task.task({
|
|
66
|
+
signal: controller.signal
|
|
67
|
+
});
|
|
68
|
+
if (task.status === "canceled" || controller.signal.aborted) return;
|
|
58
69
|
task.status = "fulfilled";
|
|
59
70
|
task.result = result;
|
|
60
71
|
task.endTime = Date.now();
|
|
61
72
|
triggerUpdate();
|
|
62
73
|
onTaskComplete?.(task);
|
|
63
74
|
} catch (error) {
|
|
75
|
+
if (task.status === "canceled" || controller.signal.aborted) return;
|
|
64
76
|
task.status = "rejected";
|
|
65
77
|
task.error = error instanceof Error ? error : new Error(String(error));
|
|
66
78
|
task.endTime = Date.now();
|
|
@@ -71,6 +83,7 @@ function useQueue(options = {}) {
|
|
|
71
83
|
}
|
|
72
84
|
} finally {
|
|
73
85
|
currentTaskIds.delete(task.id);
|
|
86
|
+
abortControllers.delete(task.id);
|
|
74
87
|
}
|
|
75
88
|
};
|
|
76
89
|
const processQueue = () => {
|
|
@@ -131,6 +144,10 @@ function useQueue(options = {}) {
|
|
|
131
144
|
taskMap.forEach(task => {
|
|
132
145
|
if (task.status === "pending" || task.status === "running") {
|
|
133
146
|
task.status = "canceled";
|
|
147
|
+
const controller = abortControllers.get(task.id);
|
|
148
|
+
if (controller) {
|
|
149
|
+
controller.abort();
|
|
150
|
+
}
|
|
134
151
|
}
|
|
135
152
|
});
|
|
136
153
|
taskMap.clear();
|
|
@@ -159,22 +176,28 @@ function useQueue(options = {}) {
|
|
|
159
176
|
const cancel = taskId => {
|
|
160
177
|
const task = taskMap.get(taskId);
|
|
161
178
|
if (task) {
|
|
162
|
-
|
|
163
|
-
|
|
179
|
+
const prevStatus = task.status;
|
|
180
|
+
task.status = "canceled";
|
|
181
|
+
const controller = abortControllers.get(taskId);
|
|
182
|
+
if (controller) {
|
|
183
|
+
controller.abort();
|
|
184
|
+
}
|
|
185
|
+
if (prevStatus === "pending") {
|
|
164
186
|
taskMap.delete(taskId);
|
|
165
187
|
const index = taskList.findIndex(t => t.id === taskId);
|
|
166
188
|
if (index > -1) taskList.splice(index, 1);
|
|
167
|
-
triggerUpdate();
|
|
168
|
-
} else if (task.status === "running") {
|
|
169
|
-
task.status = "canceled";
|
|
170
|
-
triggerUpdate();
|
|
171
189
|
}
|
|
190
|
+
triggerUpdate();
|
|
172
191
|
}
|
|
173
192
|
};
|
|
174
193
|
const cancelAll = () => {
|
|
175
194
|
taskMap.forEach(task => {
|
|
176
195
|
if (task.status === "pending" || task.status === "running") {
|
|
177
196
|
task.status = "canceled";
|
|
197
|
+
const controller = abortControllers.get(task.id);
|
|
198
|
+
if (controller) {
|
|
199
|
+
controller.abort();
|
|
200
|
+
}
|
|
178
201
|
}
|
|
179
202
|
});
|
|
180
203
|
currentTaskIds.clear();
|
package/dist/useQueue.d.ts
CHANGED
|
@@ -8,7 +8,9 @@ export interface QueueTask<T = unknown> {
|
|
|
8
8
|
/** 任务 key(用于去重) */
|
|
9
9
|
key?: string;
|
|
10
10
|
/** 任务函数 */
|
|
11
|
-
task: (
|
|
11
|
+
task: (options: {
|
|
12
|
+
signal: AbortSignal;
|
|
13
|
+
}) => Promise<T>;
|
|
12
14
|
/** 任务优先级(数字越大优先级越高) */
|
|
13
15
|
priority?: number;
|
|
14
16
|
/** 任务状态 */
|
|
@@ -73,7 +75,9 @@ export interface UseQueueReturn<T = unknown> {
|
|
|
73
75
|
/** 总数量 */
|
|
74
76
|
totalCount: ComputedRef<number>;
|
|
75
77
|
/** 添加任务 */
|
|
76
|
-
add: <R = unknown>(task: (
|
|
78
|
+
add: <R = unknown>(task: (options: {
|
|
79
|
+
signal: AbortSignal;
|
|
80
|
+
}) => Promise<R>, options?: AddTaskOptions) => string;
|
|
77
81
|
/** 移除任务 */
|
|
78
82
|
remove: (taskId: string) => void;
|
|
79
83
|
/** 清空队列 */
|
package/dist/useQueue.mjs
CHANGED
|
@@ -14,6 +14,7 @@ export function useQueue(options = {}) {
|
|
|
14
14
|
} = options;
|
|
15
15
|
const taskList = reactive([]);
|
|
16
16
|
const taskMap = /* @__PURE__ */ new Map();
|
|
17
|
+
const abortControllers = /* @__PURE__ */ new Map();
|
|
17
18
|
const isRunning = ref(false);
|
|
18
19
|
const isPaused = ref(false);
|
|
19
20
|
const currentTaskIds = /* @__PURE__ */ new Set();
|
|
@@ -40,23 +41,32 @@ export function useQueue(options = {}) {
|
|
|
40
41
|
const totalCount = computed(() => tasks.value.length);
|
|
41
42
|
const executeTask = async (task) => {
|
|
42
43
|
if (task.status === "canceled" || task.status === "running") return;
|
|
44
|
+
const controller = new AbortController();
|
|
45
|
+
abortControllers.set(task.id, controller);
|
|
43
46
|
task.status = "running";
|
|
44
47
|
task.startTime = Date.now();
|
|
45
48
|
currentTaskIds.add(task.id);
|
|
46
49
|
triggerUpdate();
|
|
47
50
|
try {
|
|
48
51
|
if (task.delay && task.delay > 0) {
|
|
49
|
-
await new Promise((resolve) =>
|
|
52
|
+
await new Promise((resolve, reject) => {
|
|
53
|
+
const timeoutId = setTimeout(resolve, task.delay);
|
|
54
|
+
controller.signal.addEventListener("abort", () => {
|
|
55
|
+
clearTimeout(timeoutId);
|
|
56
|
+
reject(new Error("Canceled"));
|
|
57
|
+
});
|
|
58
|
+
});
|
|
50
59
|
}
|
|
51
|
-
if (task.status === "canceled") return;
|
|
52
|
-
const result = await task.task();
|
|
53
|
-
if (task.status === "canceled") return;
|
|
60
|
+
if (task.status === "canceled" || controller.signal.aborted) return;
|
|
61
|
+
const result = await task.task({ signal: controller.signal });
|
|
62
|
+
if (task.status === "canceled" || controller.signal.aborted) return;
|
|
54
63
|
task.status = "fulfilled";
|
|
55
64
|
task.result = result;
|
|
56
65
|
task.endTime = Date.now();
|
|
57
66
|
triggerUpdate();
|
|
58
67
|
onTaskComplete?.(task);
|
|
59
68
|
} catch (error) {
|
|
69
|
+
if (task.status === "canceled" || controller.signal.aborted) return;
|
|
60
70
|
task.status = "rejected";
|
|
61
71
|
task.error = error instanceof Error ? error : new Error(String(error));
|
|
62
72
|
task.endTime = Date.now();
|
|
@@ -67,6 +77,7 @@ export function useQueue(options = {}) {
|
|
|
67
77
|
}
|
|
68
78
|
} finally {
|
|
69
79
|
currentTaskIds.delete(task.id);
|
|
80
|
+
abortControllers.delete(task.id);
|
|
70
81
|
}
|
|
71
82
|
};
|
|
72
83
|
const processQueue = () => {
|
|
@@ -127,6 +138,10 @@ export function useQueue(options = {}) {
|
|
|
127
138
|
taskMap.forEach((task) => {
|
|
128
139
|
if (task.status === "pending" || task.status === "running") {
|
|
129
140
|
task.status = "canceled";
|
|
141
|
+
const controller = abortControllers.get(task.id);
|
|
142
|
+
if (controller) {
|
|
143
|
+
controller.abort();
|
|
144
|
+
}
|
|
130
145
|
}
|
|
131
146
|
});
|
|
132
147
|
taskMap.clear();
|
|
@@ -155,22 +170,28 @@ export function useQueue(options = {}) {
|
|
|
155
170
|
const cancel = (taskId) => {
|
|
156
171
|
const task = taskMap.get(taskId);
|
|
157
172
|
if (task) {
|
|
158
|
-
|
|
159
|
-
|
|
173
|
+
const prevStatus = task.status;
|
|
174
|
+
task.status = "canceled";
|
|
175
|
+
const controller = abortControllers.get(taskId);
|
|
176
|
+
if (controller) {
|
|
177
|
+
controller.abort();
|
|
178
|
+
}
|
|
179
|
+
if (prevStatus === "pending") {
|
|
160
180
|
taskMap.delete(taskId);
|
|
161
181
|
const index = taskList.findIndex((t) => t.id === taskId);
|
|
162
182
|
if (index > -1) taskList.splice(index, 1);
|
|
163
|
-
triggerUpdate();
|
|
164
|
-
} else if (task.status === "running") {
|
|
165
|
-
task.status = "canceled";
|
|
166
|
-
triggerUpdate();
|
|
167
183
|
}
|
|
184
|
+
triggerUpdate();
|
|
168
185
|
}
|
|
169
186
|
};
|
|
170
187
|
const cancelAll = () => {
|
|
171
188
|
taskMap.forEach((task) => {
|
|
172
189
|
if (task.status === "pending" || task.status === "running") {
|
|
173
190
|
task.status = "canceled";
|
|
191
|
+
const controller = abortControllers.get(task.id);
|
|
192
|
+
if (controller) {
|
|
193
|
+
controller.abort();
|
|
194
|
+
}
|
|
174
195
|
}
|
|
175
196
|
});
|
|
176
197
|
currentTaskIds.clear();
|
package/dist/useRequest.cjs
CHANGED
|
@@ -16,6 +16,16 @@ function setCache(key, value, cacheTime) {
|
|
|
16
16
|
expireTime
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
|
+
function getCache(key) {
|
|
20
|
+
const cached = globalCache.get(key);
|
|
21
|
+
if (cached) {
|
|
22
|
+
if (Date.now() < cached.expireTime) {
|
|
23
|
+
return cached.data;
|
|
24
|
+
}
|
|
25
|
+
globalCache.delete(key);
|
|
26
|
+
}
|
|
27
|
+
return void 0;
|
|
28
|
+
}
|
|
19
29
|
function useRequest(service, options = {}) {
|
|
20
30
|
const {
|
|
21
31
|
manual = false,
|
|
@@ -55,7 +65,9 @@ function useRequest(service, options = {}) {
|
|
|
55
65
|
loading.value = true;
|
|
56
66
|
error.value = void 0;
|
|
57
67
|
try {
|
|
58
|
-
const response = await service(...runParams
|
|
68
|
+
const response = await service(...runParams, {
|
|
69
|
+
signal: abortController.signal
|
|
70
|
+
});
|
|
59
71
|
if (currentRunCount !== runCount.value) {
|
|
60
72
|
const cancelError = new Error("Request canceled");
|
|
61
73
|
cancelError.isCanceled = true;
|
|
@@ -95,10 +107,12 @@ function useRequest(service, options = {}) {
|
|
|
95
107
|
}
|
|
96
108
|
};
|
|
97
109
|
const cancel = () => {
|
|
110
|
+
runCount.value++;
|
|
98
111
|
if (abortController) {
|
|
99
112
|
abortController.abort();
|
|
100
113
|
abortController = null;
|
|
101
114
|
}
|
|
115
|
+
cancelFn?.();
|
|
102
116
|
loading.value = false;
|
|
103
117
|
};
|
|
104
118
|
const refresh = async () => {
|
|
@@ -166,6 +180,7 @@ function useRequestSWR(cacheKey, service, options = {}) {
|
|
|
166
180
|
const {
|
|
167
181
|
cacheTime = 10 * 60 * 1e3,
|
|
168
182
|
setCache: customSetCache,
|
|
183
|
+
getCache: customGetCache,
|
|
169
184
|
refreshOnWindowFocus = false,
|
|
170
185
|
refreshDepsWait = 1e3,
|
|
171
186
|
refreshDeps = [],
|
|
@@ -173,6 +188,7 @@ function useRequestSWR(cacheKey, service, options = {}) {
|
|
|
173
188
|
...requestOptions
|
|
174
189
|
} = options;
|
|
175
190
|
const setCacheFn = customSetCache || ((key, value) => setCache(key, value, cacheTime));
|
|
191
|
+
const getCacheFn = customGetCache || getCache;
|
|
176
192
|
const getKey = () => {
|
|
177
193
|
const key = typeof cacheKey === "function" ? cacheKey() : cacheKey;
|
|
178
194
|
return key;
|
|
@@ -182,16 +198,35 @@ function useRequestSWR(cacheKey, service, options = {}) {
|
|
|
182
198
|
data,
|
|
183
199
|
error,
|
|
184
200
|
params,
|
|
185
|
-
run,
|
|
201
|
+
run: originalRun,
|
|
186
202
|
mutate,
|
|
187
203
|
cancel,
|
|
188
|
-
refresh,
|
|
189
204
|
disabled
|
|
190
|
-
} = useRequest(key => service(key), {
|
|
205
|
+
} = useRequest((key, options2) => service(key, options2), {
|
|
191
206
|
manual,
|
|
192
207
|
defaultParams: manual ? [] : [getKey()],
|
|
193
208
|
...requestOptions
|
|
194
209
|
});
|
|
210
|
+
const initialKey = getKey();
|
|
211
|
+
if (initialKey) {
|
|
212
|
+
const cachedVal = getCacheFn(initialKey);
|
|
213
|
+
if (cachedVal !== void 0) {
|
|
214
|
+
data.value = cachedVal;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
const swrRun = async key => {
|
|
218
|
+
const cachedVal = getCacheFn(key);
|
|
219
|
+
if (cachedVal !== void 0) {
|
|
220
|
+
data.value = cachedVal;
|
|
221
|
+
}
|
|
222
|
+
return originalRun(key);
|
|
223
|
+
};
|
|
224
|
+
const swrRefresh = async () => {
|
|
225
|
+
const key = params.value[0] || getKey();
|
|
226
|
+
if (key) {
|
|
227
|
+
await swrRun(key).catch(() => {});
|
|
228
|
+
}
|
|
229
|
+
};
|
|
195
230
|
const updateCache = newData => {
|
|
196
231
|
const key = getKey();
|
|
197
232
|
if (key) {
|
|
@@ -205,27 +240,31 @@ function useRequestSWR(cacheKey, service, options = {}) {
|
|
|
205
240
|
}, {
|
|
206
241
|
immediate: true
|
|
207
242
|
});
|
|
208
|
-
if (refreshOnWindowFocus && !manual) {
|
|
243
|
+
if (refreshOnWindowFocus && !manual && (0, _vue.getCurrentInstance)()) {
|
|
244
|
+
const handleFocus = () => {
|
|
245
|
+
const key = getKey();
|
|
246
|
+
if (key && !loading.value) {
|
|
247
|
+
swrRefresh();
|
|
248
|
+
}
|
|
249
|
+
};
|
|
209
250
|
(0, _vue.onMounted)(() => {
|
|
210
|
-
const handleFocus = () => {
|
|
211
|
-
const key = getKey();
|
|
212
|
-
if (key && !loading.value) {
|
|
213
|
-
refresh();
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
251
|
window.addEventListener("visibilitychange", handleFocus);
|
|
217
252
|
window.addEventListener("focus", handleFocus);
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
253
|
+
});
|
|
254
|
+
(0, _vue.onUnmounted)(() => {
|
|
255
|
+
window.removeEventListener("visibilitychange", handleFocus);
|
|
256
|
+
window.removeEventListener("focus", handleFocus);
|
|
222
257
|
});
|
|
223
258
|
}
|
|
224
259
|
if (refreshDeps && refreshDeps.length > 0 && !manual) {
|
|
225
260
|
(0, _vue.watch)(() => refreshDeps.map(dep => dep.value), () => {
|
|
226
261
|
const key = getKey();
|
|
227
262
|
if (key) {
|
|
228
|
-
|
|
263
|
+
const cachedVal = getCacheFn(key);
|
|
264
|
+
if (cachedVal !== void 0) {
|
|
265
|
+
data.value = cachedVal;
|
|
266
|
+
}
|
|
267
|
+
setTimeout(() => swrRun(key).catch(() => {}), refreshDepsWait);
|
|
229
268
|
}
|
|
230
269
|
}, {
|
|
231
270
|
deep: true
|
|
@@ -238,10 +277,10 @@ function useRequestSWR(cacheKey, service, options = {}) {
|
|
|
238
277
|
params,
|
|
239
278
|
loadingMore: (0, _vue.ref)(false),
|
|
240
279
|
noMore: (0, _vue.ref)(false),
|
|
241
|
-
run,
|
|
280
|
+
run: swrRun,
|
|
242
281
|
mutate,
|
|
243
282
|
cancel,
|
|
244
|
-
refresh,
|
|
283
|
+
refresh: swrRefresh,
|
|
245
284
|
loadMore: async () => {
|
|
246
285
|
return Promise.resolve();
|
|
247
286
|
},
|
package/dist/useRequest.d.ts
CHANGED
|
@@ -14,7 +14,9 @@ export interface UseRequestOptions<TData, TParams extends unknown[] = unknown[]>
|
|
|
14
14
|
/** 请求实例 */
|
|
15
15
|
request?: Request;
|
|
16
16
|
/** 请求函数 */
|
|
17
|
-
service?: (...args: TParams
|
|
17
|
+
service?: (...args: [...TParams, {
|
|
18
|
+
signal?: AbortSignal;
|
|
19
|
+
}?] | unknown[]) => Promise<RequestResponse<TData>>;
|
|
18
20
|
/** 格式化返回数据 */
|
|
19
21
|
formatResult?: (response: RequestResponse<TData>) => TData;
|
|
20
22
|
/** 成功回调 */
|
|
@@ -108,7 +110,9 @@ export declare function useRequest<TData = unknown, TParams extends unknown[] =
|
|
|
108
110
|
* { cacheKey: 'user' }
|
|
109
111
|
* )
|
|
110
112
|
*/
|
|
111
|
-
export declare function useRequestSWR<TData = unknown>(cacheKey: string | (() => string), service: (key: string
|
|
113
|
+
export declare function useRequestSWR<TData = unknown>(cacheKey: string | (() => string), service: (key: string, options?: {
|
|
114
|
+
signal?: AbortSignal;
|
|
115
|
+
}) => Promise<RequestResponse<TData>>, options?: UseRequestSWROptions<TData, [string]>): UseRequestReturn<TData, [string]>;
|
|
112
116
|
/**
|
|
113
117
|
* useRequestPolling - 带轮询的请求 Hook
|
|
114
118
|
*
|
package/dist/useRequest.mjs
CHANGED
|
@@ -4,7 +4,8 @@ import {
|
|
|
4
4
|
computed,
|
|
5
5
|
watch,
|
|
6
6
|
onMounted,
|
|
7
|
-
onUnmounted
|
|
7
|
+
onUnmounted,
|
|
8
|
+
getCurrentInstance
|
|
8
9
|
} from "vue";
|
|
9
10
|
import { debounce, throttle } from "@yh-ui/utils";
|
|
10
11
|
const globalCache = /* @__PURE__ */ new Map();
|
|
@@ -12,6 +13,16 @@ function setCache(key, value, cacheTime) {
|
|
|
12
13
|
const expireTime = Date.now() + (cacheTime || 5 * 60 * 1e3);
|
|
13
14
|
globalCache.set(key, { data: value, expireTime });
|
|
14
15
|
}
|
|
16
|
+
function getCache(key) {
|
|
17
|
+
const cached = globalCache.get(key);
|
|
18
|
+
if (cached) {
|
|
19
|
+
if (Date.now() < cached.expireTime) {
|
|
20
|
+
return cached.data;
|
|
21
|
+
}
|
|
22
|
+
globalCache.delete(key);
|
|
23
|
+
}
|
|
24
|
+
return void 0;
|
|
25
|
+
}
|
|
15
26
|
export function useRequest(service, options = {}) {
|
|
16
27
|
const {
|
|
17
28
|
manual = false,
|
|
@@ -51,7 +62,7 @@ export function useRequest(service, options = {}) {
|
|
|
51
62
|
loading.value = true;
|
|
52
63
|
error.value = void 0;
|
|
53
64
|
try {
|
|
54
|
-
const response = await service(...runParams);
|
|
65
|
+
const response = await service(...runParams, { signal: abortController.signal });
|
|
55
66
|
if (currentRunCount !== runCount.value) {
|
|
56
67
|
const cancelError = new Error("Request canceled");
|
|
57
68
|
cancelError.isCanceled = true;
|
|
@@ -91,10 +102,12 @@ export function useRequest(service, options = {}) {
|
|
|
91
102
|
}
|
|
92
103
|
};
|
|
93
104
|
const cancel = () => {
|
|
105
|
+
runCount.value++;
|
|
94
106
|
if (abortController) {
|
|
95
107
|
abortController.abort();
|
|
96
108
|
abortController = null;
|
|
97
109
|
}
|
|
110
|
+
cancelFn?.();
|
|
98
111
|
loading.value = false;
|
|
99
112
|
};
|
|
100
113
|
const refresh = async () => {
|
|
@@ -173,6 +186,7 @@ export function useRequestSWR(cacheKey, service, options = {}) {
|
|
|
173
186
|
const {
|
|
174
187
|
cacheTime = 10 * 60 * 1e3,
|
|
175
188
|
setCache: customSetCache,
|
|
189
|
+
getCache: customGetCache,
|
|
176
190
|
refreshOnWindowFocus = false,
|
|
177
191
|
refreshDepsWait = 1e3,
|
|
178
192
|
refreshDeps = [],
|
|
@@ -180,15 +194,49 @@ export function useRequestSWR(cacheKey, service, options = {}) {
|
|
|
180
194
|
...requestOptions
|
|
181
195
|
} = options;
|
|
182
196
|
const setCacheFn = customSetCache || ((key, value) => setCache(key, value, cacheTime));
|
|
197
|
+
const getCacheFn = customGetCache || getCache;
|
|
183
198
|
const getKey = () => {
|
|
184
199
|
const key = typeof cacheKey === "function" ? cacheKey() : cacheKey;
|
|
185
200
|
return key;
|
|
186
201
|
};
|
|
187
|
-
const {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
202
|
+
const {
|
|
203
|
+
loading,
|
|
204
|
+
data,
|
|
205
|
+
error,
|
|
206
|
+
params,
|
|
207
|
+
run: originalRun,
|
|
208
|
+
mutate,
|
|
209
|
+
cancel,
|
|
210
|
+
disabled
|
|
211
|
+
} = useRequest(
|
|
212
|
+
(key, options2) => service(key, options2),
|
|
213
|
+
{
|
|
214
|
+
manual,
|
|
215
|
+
defaultParams: manual ? [] : [getKey()],
|
|
216
|
+
...requestOptions
|
|
217
|
+
}
|
|
218
|
+
);
|
|
219
|
+
const initialKey = getKey();
|
|
220
|
+
if (initialKey) {
|
|
221
|
+
const cachedVal = getCacheFn(initialKey);
|
|
222
|
+
if (cachedVal !== void 0) {
|
|
223
|
+
data.value = cachedVal;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
const swrRun = async (key) => {
|
|
227
|
+
const cachedVal = getCacheFn(key);
|
|
228
|
+
if (cachedVal !== void 0) {
|
|
229
|
+
data.value = cachedVal;
|
|
230
|
+
}
|
|
231
|
+
return originalRun(key);
|
|
232
|
+
};
|
|
233
|
+
const swrRefresh = async () => {
|
|
234
|
+
const key = params.value[0] || getKey();
|
|
235
|
+
if (key) {
|
|
236
|
+
await swrRun(key).catch(() => {
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
};
|
|
192
240
|
const updateCache = (newData) => {
|
|
193
241
|
const key = getKey();
|
|
194
242
|
if (key) {
|
|
@@ -204,20 +252,20 @@ export function useRequestSWR(cacheKey, service, options = {}) {
|
|
|
204
252
|
},
|
|
205
253
|
{ immediate: true }
|
|
206
254
|
);
|
|
207
|
-
if (refreshOnWindowFocus && !manual) {
|
|
255
|
+
if (refreshOnWindowFocus && !manual && getCurrentInstance()) {
|
|
256
|
+
const handleFocus = () => {
|
|
257
|
+
const key = getKey();
|
|
258
|
+
if (key && !loading.value) {
|
|
259
|
+
swrRefresh();
|
|
260
|
+
}
|
|
261
|
+
};
|
|
208
262
|
onMounted(() => {
|
|
209
|
-
const handleFocus = () => {
|
|
210
|
-
const key = getKey();
|
|
211
|
-
if (key && !loading.value) {
|
|
212
|
-
refresh();
|
|
213
|
-
}
|
|
214
|
-
};
|
|
215
263
|
window.addEventListener("visibilitychange", handleFocus);
|
|
216
264
|
window.addEventListener("focus", handleFocus);
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
265
|
+
});
|
|
266
|
+
onUnmounted(() => {
|
|
267
|
+
window.removeEventListener("visibilitychange", handleFocus);
|
|
268
|
+
window.removeEventListener("focus", handleFocus);
|
|
221
269
|
});
|
|
222
270
|
}
|
|
223
271
|
if (refreshDeps && refreshDeps.length > 0 && !manual) {
|
|
@@ -226,7 +274,11 @@ export function useRequestSWR(cacheKey, service, options = {}) {
|
|
|
226
274
|
() => {
|
|
227
275
|
const key = getKey();
|
|
228
276
|
if (key) {
|
|
229
|
-
|
|
277
|
+
const cachedVal = getCacheFn(key);
|
|
278
|
+
if (cachedVal !== void 0) {
|
|
279
|
+
data.value = cachedVal;
|
|
280
|
+
}
|
|
281
|
+
setTimeout(() => swrRun(key).catch(() => {
|
|
230
282
|
}), refreshDepsWait);
|
|
231
283
|
}
|
|
232
284
|
},
|
|
@@ -240,10 +292,10 @@ export function useRequestSWR(cacheKey, service, options = {}) {
|
|
|
240
292
|
params,
|
|
241
293
|
loadingMore: ref(false),
|
|
242
294
|
noMore: ref(false),
|
|
243
|
-
run,
|
|
295
|
+
run: swrRun,
|
|
244
296
|
mutate,
|
|
245
297
|
cancel,
|
|
246
|
-
refresh,
|
|
298
|
+
refresh: swrRefresh,
|
|
247
299
|
loadMore: async () => {
|
|
248
300
|
return Promise.resolve();
|
|
249
301
|
},
|
package/dist/websocket.cjs
CHANGED
|
@@ -20,6 +20,9 @@ class WebSocketClient {
|
|
|
20
20
|
heartbeatTimer = null;
|
|
21
21
|
heartbeatTimeoutTimer = null;
|
|
22
22
|
messageQueue = [];
|
|
23
|
+
isActivelyClosed = false;
|
|
24
|
+
messageIdCounter = 0;
|
|
25
|
+
pendingRequests = /* @__PURE__ */new Map();
|
|
23
26
|
// 回调
|
|
24
27
|
onOpenCallback = null;
|
|
25
28
|
onCloseCallback = null;
|
|
@@ -84,6 +87,7 @@ class WebSocketClient {
|
|
|
84
87
|
* 连接
|
|
85
88
|
*/
|
|
86
89
|
connect() {
|
|
90
|
+
this.isActivelyClosed = false;
|
|
87
91
|
return new Promise((resolve, reject) => {
|
|
88
92
|
if (!isWebSocketSupported()) {
|
|
89
93
|
const error = new Error("WebSocket is not supported in this environment");
|
|
@@ -118,6 +122,7 @@ class WebSocketClient {
|
|
|
118
122
|
* 断开连接
|
|
119
123
|
*/
|
|
120
124
|
disconnect(code = 1e3, reason = "Client disconnect") {
|
|
125
|
+
this.isActivelyClosed = true;
|
|
121
126
|
this.clearTimers();
|
|
122
127
|
this.setState("disconnecting");
|
|
123
128
|
if (this.ws) {
|
|
@@ -125,6 +130,7 @@ class WebSocketClient {
|
|
|
125
130
|
this.ws = null;
|
|
126
131
|
}
|
|
127
132
|
this.setState("disconnected");
|
|
133
|
+
this.rejectAllPendingRequests("WebSocket disconnected: " + reason);
|
|
128
134
|
}
|
|
129
135
|
/**
|
|
130
136
|
* 发送消息
|
|
@@ -143,25 +149,24 @@ class WebSocketClient {
|
|
|
143
149
|
*/
|
|
144
150
|
sendAndWait(data, timeout = 3e4) {
|
|
145
151
|
return new Promise((resolve, reject) => {
|
|
146
|
-
const messageId = Date.now().
|
|
152
|
+
const messageId = `msg_${Date.now()}_${++this.messageIdCounter}`;
|
|
147
153
|
const timer = setTimeout(() => {
|
|
154
|
+
this.pendingRequests.delete(messageId);
|
|
148
155
|
reject(new Error("WebSocket message timeout"));
|
|
149
156
|
}, timeout);
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
resolve(decoded.result);
|
|
157
|
-
} else {
|
|
158
|
-
originalCallback?.(message);
|
|
159
|
-
}
|
|
160
|
-
};
|
|
161
|
-
this.send({
|
|
157
|
+
this.pendingRequests.set(messageId, {
|
|
158
|
+
resolve,
|
|
159
|
+
reject,
|
|
160
|
+
timer
|
|
161
|
+
});
|
|
162
|
+
const payload = typeof data === "object" && data !== null ? {
|
|
162
163
|
id: messageId,
|
|
163
164
|
...data
|
|
164
|
-
}
|
|
165
|
+
} : {
|
|
166
|
+
id: messageId,
|
|
167
|
+
data
|
|
168
|
+
};
|
|
169
|
+
this.send(payload);
|
|
165
170
|
});
|
|
166
171
|
}
|
|
167
172
|
/**
|
|
@@ -206,9 +211,10 @@ class WebSocketClient {
|
|
|
206
211
|
this.ws = null;
|
|
207
212
|
this.clearTimers();
|
|
208
213
|
this.setState("disconnected");
|
|
209
|
-
if (this.options.reconnect && this.reconnectAttempts < this.options.reconnectMaxAttempts) {
|
|
214
|
+
if (!this.isActivelyClosed && this.options.reconnect && this.reconnectAttempts < this.options.reconnectMaxAttempts) {
|
|
210
215
|
this.reconnect();
|
|
211
216
|
}
|
|
217
|
+
this.rejectAllPendingRequests(`WebSocket disconnected: ${event.reason || "Closed"}`);
|
|
212
218
|
this.onCloseCallback?.(event.code, event.reason);
|
|
213
219
|
}
|
|
214
220
|
handleError(event) {
|
|
@@ -234,6 +240,18 @@ class WebSocketClient {
|
|
|
234
240
|
timestamp: Date.now()
|
|
235
241
|
};
|
|
236
242
|
this.lastMessage.value = message;
|
|
243
|
+
if (data && typeof data === "object") {
|
|
244
|
+
const decoded = data;
|
|
245
|
+
if (decoded.id && this.pendingRequests.has(decoded.id)) {
|
|
246
|
+
const pending = this.pendingRequests.get(decoded.id);
|
|
247
|
+
if (pending) {
|
|
248
|
+
clearTimeout(pending.timer);
|
|
249
|
+
this.pendingRequests.delete(decoded.id);
|
|
250
|
+
pending.resolve(decoded.result);
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
237
255
|
this.onMessageCallback?.(message);
|
|
238
256
|
}
|
|
239
257
|
reconnect() {
|
|
@@ -271,6 +289,13 @@ class WebSocketClient {
|
|
|
271
289
|
}
|
|
272
290
|
this.clearHeartbeatTimeout();
|
|
273
291
|
}
|
|
292
|
+
rejectAllPendingRequests(reason = "WebSocket disconnected") {
|
|
293
|
+
for (const [, pending] of this.pendingRequests.entries()) {
|
|
294
|
+
clearTimeout(pending.timer);
|
|
295
|
+
pending.reject(new Error(reason));
|
|
296
|
+
}
|
|
297
|
+
this.pendingRequests.clear();
|
|
298
|
+
}
|
|
274
299
|
/**
|
|
275
300
|
* 清理资源
|
|
276
301
|
*/
|
package/dist/websocket.d.ts
CHANGED
|
@@ -62,6 +62,9 @@ export declare class WebSocketClient {
|
|
|
62
62
|
private heartbeatTimer;
|
|
63
63
|
private heartbeatTimeoutTimer;
|
|
64
64
|
private messageQueue;
|
|
65
|
+
private isActivelyClosed;
|
|
66
|
+
private messageIdCounter;
|
|
67
|
+
private pendingRequests;
|
|
65
68
|
private onOpenCallback;
|
|
66
69
|
private onCloseCallback;
|
|
67
70
|
private onErrorCallback;
|
|
@@ -111,6 +114,7 @@ export declare class WebSocketClient {
|
|
|
111
114
|
private startHeartbeat;
|
|
112
115
|
private clearHeartbeatTimeout;
|
|
113
116
|
private clearTimers;
|
|
117
|
+
private rejectAllPendingRequests;
|
|
114
118
|
/**
|
|
115
119
|
* 清理资源
|
|
116
120
|
*/
|
package/dist/websocket.mjs
CHANGED
|
@@ -11,6 +11,9 @@ export class WebSocketClient {
|
|
|
11
11
|
heartbeatTimer = null;
|
|
12
12
|
heartbeatTimeoutTimer = null;
|
|
13
13
|
messageQueue = [];
|
|
14
|
+
isActivelyClosed = false;
|
|
15
|
+
messageIdCounter = 0;
|
|
16
|
+
pendingRequests = /* @__PURE__ */ new Map();
|
|
14
17
|
// 回调
|
|
15
18
|
onOpenCallback = null;
|
|
16
19
|
onCloseCallback = null;
|
|
@@ -75,6 +78,7 @@ export class WebSocketClient {
|
|
|
75
78
|
* 连接
|
|
76
79
|
*/
|
|
77
80
|
connect() {
|
|
81
|
+
this.isActivelyClosed = false;
|
|
78
82
|
return new Promise((resolve, reject) => {
|
|
79
83
|
if (!isWebSocketSupported()) {
|
|
80
84
|
const error = new Error("WebSocket is not supported in this environment");
|
|
@@ -109,6 +113,7 @@ export class WebSocketClient {
|
|
|
109
113
|
* 断开连接
|
|
110
114
|
*/
|
|
111
115
|
disconnect(code = 1e3, reason = "Client disconnect") {
|
|
116
|
+
this.isActivelyClosed = true;
|
|
112
117
|
this.clearTimers();
|
|
113
118
|
this.setState("disconnecting");
|
|
114
119
|
if (this.ws) {
|
|
@@ -116,6 +121,7 @@ export class WebSocketClient {
|
|
|
116
121
|
this.ws = null;
|
|
117
122
|
}
|
|
118
123
|
this.setState("disconnected");
|
|
124
|
+
this.rejectAllPendingRequests("WebSocket disconnected: " + reason);
|
|
119
125
|
}
|
|
120
126
|
/**
|
|
121
127
|
* 发送消息
|
|
@@ -134,22 +140,14 @@ export class WebSocketClient {
|
|
|
134
140
|
*/
|
|
135
141
|
sendAndWait(data, timeout = 3e4) {
|
|
136
142
|
return new Promise((resolve, reject) => {
|
|
137
|
-
const messageId = Date.now().
|
|
143
|
+
const messageId = `msg_${Date.now()}_${++this.messageIdCounter}`;
|
|
138
144
|
const timer = setTimeout(() => {
|
|
145
|
+
this.pendingRequests.delete(messageId);
|
|
139
146
|
reject(new Error("WebSocket message timeout"));
|
|
140
147
|
}, timeout);
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
if (decoded && decoded.id === messageId) {
|
|
145
|
-
clearTimeout(timer);
|
|
146
|
-
this.onMessageCallback = originalCallback;
|
|
147
|
-
resolve(decoded.result);
|
|
148
|
-
} else {
|
|
149
|
-
originalCallback?.(message);
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
this.send({ id: messageId, ...data });
|
|
148
|
+
this.pendingRequests.set(messageId, { resolve, reject, timer });
|
|
149
|
+
const payload = typeof data === "object" && data !== null ? { id: messageId, ...data } : { id: messageId, data };
|
|
150
|
+
this.send(payload);
|
|
153
151
|
});
|
|
154
152
|
}
|
|
155
153
|
/**
|
|
@@ -194,9 +192,10 @@ export class WebSocketClient {
|
|
|
194
192
|
this.ws = null;
|
|
195
193
|
this.clearTimers();
|
|
196
194
|
this.setState("disconnected");
|
|
197
|
-
if (this.options.reconnect && this.reconnectAttempts < this.options.reconnectMaxAttempts) {
|
|
195
|
+
if (!this.isActivelyClosed && this.options.reconnect && this.reconnectAttempts < this.options.reconnectMaxAttempts) {
|
|
198
196
|
this.reconnect();
|
|
199
197
|
}
|
|
198
|
+
this.rejectAllPendingRequests(`WebSocket disconnected: ${event.reason || "Closed"}`);
|
|
200
199
|
this.onCloseCallback?.(event.code, event.reason);
|
|
201
200
|
}
|
|
202
201
|
handleError(event) {
|
|
@@ -222,6 +221,18 @@ export class WebSocketClient {
|
|
|
222
221
|
timestamp: Date.now()
|
|
223
222
|
};
|
|
224
223
|
this.lastMessage.value = message;
|
|
224
|
+
if (data && typeof data === "object") {
|
|
225
|
+
const decoded = data;
|
|
226
|
+
if (decoded.id && this.pendingRequests.has(decoded.id)) {
|
|
227
|
+
const pending = this.pendingRequests.get(decoded.id);
|
|
228
|
+
if (pending) {
|
|
229
|
+
clearTimeout(pending.timer);
|
|
230
|
+
this.pendingRequests.delete(decoded.id);
|
|
231
|
+
pending.resolve(decoded.result);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
225
236
|
this.onMessageCallback?.(message);
|
|
226
237
|
}
|
|
227
238
|
reconnect() {
|
|
@@ -263,6 +274,13 @@ export class WebSocketClient {
|
|
|
263
274
|
}
|
|
264
275
|
this.clearHeartbeatTimeout();
|
|
265
276
|
}
|
|
277
|
+
rejectAllPendingRequests(reason = "WebSocket disconnected") {
|
|
278
|
+
for (const [, pending] of this.pendingRequests.entries()) {
|
|
279
|
+
clearTimeout(pending.timer);
|
|
280
|
+
pending.reject(new Error(reason));
|
|
281
|
+
}
|
|
282
|
+
this.pendingRequests.clear();
|
|
283
|
+
}
|
|
266
284
|
/**
|
|
267
285
|
* 清理资源
|
|
268
286
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yh-ui/request",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.54",
|
|
4
4
|
"description": "YH-UI HTTP request hooks - Enterprise-grade request management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"postpack": "node ../../scripts/prepare-package-manifest.mjs restore"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@yh-ui/utils": "^1.0.
|
|
35
|
+
"@yh-ui/utils": "^1.0.54"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"vue": "^3.5.35",
|