Skip to content

Commit da23d66

Browse files
committed
feat: 在切换厂商、切换测试场景和发起新测试时自动中止当前请求
1 parent 1d1052f commit da23d66

File tree

1 file changed

+37
-11
lines changed

1 file changed

+37
-11
lines changed

assets/js/script.js

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,17 @@
3535
// Waiting loader state
3636
let requestPending = false;
3737
let waitingEl = null;
38+
let currentAbortController = null;
39+
40+
// Abort current request helper
41+
function abortCurrentRequest(){
42+
if(currentAbortController){
43+
currentAbortController.abort();
44+
currentAbortController = null;
45+
}
46+
requestPending = false;
47+
hideWaiting();
48+
}
3849

3950
// LocalStorage helpers
4051
function loadConfigs(){
@@ -664,6 +675,7 @@
664675

665676
// 切换厂商
666677
function setActiveVendor(vendor){
678+
abortCurrentRequest();
667679
currentVendor = vendor;
668680
$$('#vendorType .seg-btn').forEach(btn => btn.classList.toggle('active', btn.dataset.vendor === vendor));
669681
renderTestButtons(vendor);
@@ -672,6 +684,7 @@
672684

673685
// 切换测试场景
674686
function setActiveScenario(scenario){
687+
abortCurrentRequest();
675688
$$('#testType .seg-btn').forEach(btn => btn.classList.toggle('active', btn.dataset.scenario === scenario));
676689
// 查找对应的默认输入
677690
const tests = vendorTests[currentVendor] || [];
@@ -702,6 +715,7 @@
702715

703716
// Test function call flow (multiple scenarios)
704717
testBtn.addEventListener('click', async () => {
718+
abortCurrentRequest();
705719
const apiUrl = apiUrlEl.value.trim();
706720
const apiKey = apiKeyEl.value.trim();
707721
const model = (modelEl.value || SYSTEM_DEFAULTS.model).trim();
@@ -711,6 +725,9 @@
711725
// 发起新请求前自动清空历史记录
712726
clearResults();
713727

728+
currentAbortController = new AbortController();
729+
const signal = currentAbortController.signal;
730+
714731
const scenario = testTypeWrap.querySelector('.seg-btn.active')?.dataset.scenario || 'openai_tools';
715732
const endpoint = buildEndpoint(apiUrl);
716733
const geminiEndpoint = buildGeminiEndpoint(apiUrl, model, apiKey);
@@ -744,7 +761,7 @@
744761
addMessage('user', '消息 #1', requestBody1.messages[0]);
745762

746763
const t1Start = Date.now();
747-
const r1 = await fetchAndParse(endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` }, body: JSON.stringify(requestBody1) });
764+
const r1 = await fetchAndParse(endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` }, body: JSON.stringify(requestBody1), signal });
748765
const data1 = ensureJsonOrThrow(r1);
749766
const t1Duration = Date.now() - t1Start;
750767
addBlock('响应 #1', data1, t1Duration);
@@ -776,7 +793,7 @@
776793
const requestBody2 = { model, messages: [ requestBody1.messages[0], assistantMsg, toolMessage ] };
777794
const t2Start = Date.now();
778795
addBlock('请求 #2', requestBody2);
779-
const r2 = await fetchAndParse(endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` }, body: JSON.stringify(requestBody2) });
796+
const r2 = await fetchAndParse(endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` }, body: JSON.stringify(requestBody2), signal });
780797
const data2 = ensureJsonOrThrow(r2);
781798
const t2Duration = Date.now() - t2Start;
782799
addBlock('响应 #2', data2, t2Duration);
@@ -803,7 +820,8 @@
803820
const aR1 = await fetchAndParse(anthropicEndpoint, {
804821
method: 'POST',
805822
headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey, 'anthropic-version': '2023-06-01' },
806-
body: JSON.stringify(aReq1)
823+
body: JSON.stringify(aReq1),
824+
signal
807825
});
808826
const aData1 = ensureJsonOrThrow(aR1);
809827
const aT1Duration = Date.now() - aT1Start;
@@ -841,7 +859,8 @@
841859
const aR2 = await fetchAndParse(anthropicEndpoint, {
842860
method: 'POST',
843861
headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey, 'anthropic-version': '2023-06-01' },
844-
body: JSON.stringify(aReq2)
862+
body: JSON.stringify(aReq2),
863+
signal
845864
});
846865
const aData2 = ensureJsonOrThrow(aR2);
847866
const aT2Duration = Date.now() - aT2Start;
@@ -865,7 +884,7 @@
865884
addBlock('请求 #1', gReq1);
866885
addMessage('user', '消息 #1', { role: 'user', parts: [{ text: userText }] });
867886
const gT1Start = Date.now();
868-
const gR1 = await fetchAndParse(geminiEndpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(gReq1) });
887+
const gR1 = await fetchAndParse(geminiEndpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(gReq1), signal });
869888
const gData1 = ensureJsonOrThrow(gR1);
870889
const gT1Duration = Date.now() - gT1Start;
871890
addBlock('响应 #1', gData1, gT1Duration);
@@ -902,7 +921,7 @@
902921
};
903922
const gT2Start = Date.now();
904923
addBlock('请求 #2', gReq2);
905-
const gR2 = await fetchAndParse(geminiEndpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(gReq2) });
924+
const gR2 = await fetchAndParse(geminiEndpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(gReq2), signal });
906925
const gData2 = ensureJsonOrThrow(gR2);
907926
const gT2Duration = Date.now() - gT2Start;
908927
addBlock('响应 #2', gData2, gT2Duration);
@@ -934,7 +953,8 @@
934953
const rtR1 = await fetchAndParse(responsesEndpoint, {
935954
method: 'POST',
936955
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` },
937-
body: JSON.stringify(rtReq1)
956+
body: JSON.stringify(rtReq1),
957+
signal
938958
});
939959
const rtData1 = ensureJsonOrThrow(rtR1);
940960
const rtT1Duration = Date.now() - rtT1Start;
@@ -982,7 +1002,8 @@
9821002
const rtR2 = await fetchAndParse(responsesEndpoint, {
9831003
method: 'POST',
9841004
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` },
985-
body: JSON.stringify(rtReq2)
1005+
body: JSON.stringify(rtReq2),
1006+
signal
9861007
});
9871008
const rtData2 = ensureJsonOrThrow(rtR2);
9881009
const rtT2Duration = Date.now() - rtT2Start;
@@ -1012,7 +1033,8 @@
10121033
const rR = await fetchAndParse(responsesEndpoint, {
10131034
method: 'POST',
10141035
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` },
1015-
body: JSON.stringify(rReq)
1036+
body: JSON.stringify(rReq),
1037+
signal
10161038
});
10171039
const rData = ensureJsonOrThrow(rR);
10181040
const rTDuration = Date.now() - rTStart;
@@ -1050,7 +1072,7 @@
10501072
addBlock('请求 #1', gReq);
10511073
addMessage('user', '消息', gReq.contents[0]);
10521074
const gsTStart = Date.now();
1053-
const gR = await fetchAndParse(geminiEndpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(gReq) });
1075+
const gR = await fetchAndParse(geminiEndpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(gReq), signal });
10541076
const gData = ensureJsonOrThrow(gR);
10551077
const gsTDuration = Date.now() - gsTStart;
10561078
addBlock('响应 #1', gData, gsTDuration);
@@ -1073,7 +1095,7 @@
10731095
addBlock('请求 #1', gReq);
10741096
addMessage('user', '消息', gReq.contents[0]);
10751097
const guTStart = Date.now();
1076-
const gR = await fetchAndParse(geminiEndpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(gReq) });
1098+
const gR = await fetchAndParse(geminiEndpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(gReq), signal });
10771099
const gData = ensureJsonOrThrow(gR);
10781100
const guTDuration = Date.now() - guTStart;
10791101
addBlock('响应 #1', gData, guTDuration);
@@ -1090,6 +1112,10 @@
10901112
}
10911113

10921114
}catch(err){
1115+
if(err.name === 'AbortError'){
1116+
console.log('Request aborted by user');
1117+
return;
1118+
}
10931119
console.error(err);
10941120
// 清空顶部简要错误,改为在时间线内展示红色错误块
10951121
errorMessage.textContent = '';

0 commit comments

Comments
 (0)