فهرست منبع

feat: support for `signal` in `fetchAdvanced()`

Sv443 5 ماه پیش
والد
کامیت
1ecd63c
4فایلهای تغییر یافته به همراه31 افزوده شده و 16 حذف شده
  1. 5 0
      .changeset/famous-flowers-develop.md
  2. 10 2
      README.md
  3. 15 14
      lib/misc.ts
  4. 1 0
      package.json

+ 5 - 0
.changeset/famous-flowers-develop.md

@@ -0,0 +1,5 @@
+---
+"@sv443-network/userutils": minor
+---
+
+Added support for the `signal` property in `fetchAdvanced()`

+ 10 - 2
README.md

@@ -1775,24 +1775,32 @@ fetchAdvanced(input: string | Request | URL, options?: {
   
 A drop-in replacement for the native `fetch()` function that adds options like a timeout property.  
 The timeout will default to 10 seconds if left undefined. Set it to a negative number to disable the timeout.  
-Note that the `signal` option will be overwritten if passed.  
   
 <details><summary><b>Example - click to view</b></summary>
 
 ```ts
 import { fetchAdvanced } from "@sv443-network/userutils";
 
+const { signal, abort } = new AbortController();
+
 fetchAdvanced("https://jokeapi.dev/joke/Any?safe-mode", {
+  // times out after 5 seconds:
   timeout: 5000,
-  // also accepts any other fetch options like headers:
+  // also accepts any other fetch options like headers and signal:
   headers: {
     "Accept": "text/plain",
   },
+  // makes the request abortable:
+  signal,
 }).then(async (response) => {
   console.log("Fetch data:", await response.text());
 }).catch((err) => {
   console.error("Fetch error:", err);
 });
+
+document.querySelector("button#cancel")?.addEventListener("click", () => {
+  abort();
+});
 ```
 </details>
 

+ 15 - 14
lib/misc.ts

@@ -46,42 +46,43 @@ export function debounce<
   timeout = 300,
   edge: "rising" | "falling" = "falling"
 ): (...args: TArgs[]) => void {
-  let timer: NodeJS.Timeout | undefined;
+  let id: ReturnType<typeof setTimeout> | undefined;
 
   return function(...args: TArgs[]) {
     if(edge === "rising") {
-      if(!timer) {
+      if(!id) {
         func.apply(this, args);
-        timer = setTimeout(() => timer = undefined, timeout);
+        id = setTimeout(() => id = undefined, timeout);
       }
     }
     else {
-      clearTimeout(timer);
-      timer = setTimeout(() => func.apply(this, args), timeout);
+      clearTimeout(id);
+      id = setTimeout(() => func.apply(this, args), timeout);
     }
   };
 }
 
 /** Options for the `fetchAdvanced()` function */
-export type FetchAdvancedOpts = Prettify<Omit<
-  RequestInit & Partial<{
+export type FetchAdvancedOpts = Prettify<
+  Partial<{
     /** Timeout in milliseconds after which the fetch call will be canceled with an AbortController signal */
     timeout: number;
-  }>,
-  "signal"
->>;
+  }> & RequestInit
+>;
 
 /** Calls the fetch API with special options like a timeout */
 export async function fetchAdvanced(input: RequestInfo | URL, options: FetchAdvancedOpts = {}): Promise<Response> {
   const { timeout = 10000 } = options;
+  const { signal, abort } = new AbortController();
+
+  options.signal?.addEventListener("abort", abort);
 
   let signalOpts: Partial<RequestInit> = {},
-    id: NodeJS.Timeout | undefined = undefined;
+    id: ReturnType<typeof setTimeout> | undefined = undefined;
 
   if(timeout >= 0) {
-    const controller = new AbortController();
-    id = setTimeout(() => controller.abort(), timeout);
-    signalOpts = { signal: controller.signal };
+    id = setTimeout(() => abort(), timeout);
+    signalOpts = { signal };
   }
 
   try {

+ 1 - 0
package.json

@@ -27,6 +27,7 @@
     "update-jsr-version": "npm run node-ts -- ./tools/update-jsr-version.mts",
     "publish-package": "changeset publish",
     "publish-package-jsr": "npm run update-jsr-version && npx jsr publish --allow-dirty",
+    "change": "changeset",
     "node-ts": "node --no-warnings=ExperimentalWarning --enable-source-maps --loader ts-node/esm",
     "test-serve": "npm run node-ts -- ./test/TestPage/server.mts",
     "test-dev": "cd test/TestScript && npm run dev",