@sohanemon/utils 5.1.7 → 5.2.0
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.
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
type Task = () => Promise<void> | void;
|
|
2
|
-
interface ScheduleOpts {
|
|
1
|
+
export type Task = () => Promise<void> | void;
|
|
2
|
+
export interface ScheduleOpts {
|
|
3
3
|
retry?: number;
|
|
4
4
|
delay?: number;
|
|
5
|
+
timeout?: number;
|
|
5
6
|
}
|
|
6
7
|
/**
|
|
7
8
|
* Runs a function asynchronously in the background.
|
|
8
9
|
* Returns immediately, retries on failure if configured.
|
|
10
|
+
* Logs total time taken.
|
|
9
11
|
*/
|
|
10
12
|
export declare function schedule(task: Task, options?: ScheduleOpts): void;
|
|
11
|
-
export {};
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Runs a function asynchronously in the background.
|
|
3
3
|
* Returns immediately, retries on failure if configured.
|
|
4
|
+
* Logs total time taken.
|
|
4
5
|
*/
|
|
5
6
|
export function schedule(task, options = {}) {
|
|
6
7
|
const { retry = 0, delay = 0 } = options;
|
|
8
|
+
const start = Date.now();
|
|
7
9
|
const attempt = async (triesLeft) => {
|
|
8
10
|
try {
|
|
9
11
|
await task();
|
|
12
|
+
const total = Date.now() - start;
|
|
13
|
+
console.log(`⚡[schedule.ts] Completed in ${total}ms`);
|
|
10
14
|
}
|
|
11
15
|
catch (err) {
|
|
12
16
|
console.log('⚡[schedule.ts] err:', err);
|
|
@@ -14,6 +18,10 @@ export function schedule(task, options = {}) {
|
|
|
14
18
|
console.log(`⚡[schedule.ts] Retrying in ${delay}ms...`);
|
|
15
19
|
setTimeout(() => attempt(triesLeft - 1), delay);
|
|
16
20
|
}
|
|
21
|
+
else {
|
|
22
|
+
const total = Date.now() - start;
|
|
23
|
+
console.log(`⚡[schedule.ts] Failed after ${total}ms`);
|
|
24
|
+
}
|
|
17
25
|
}
|
|
18
26
|
};
|
|
19
27
|
// Schedule immediately
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ScheduleOpts } from '../functions';
|
|
3
|
+
import { Task } from '../functions/schedule';
|
|
4
|
+
/**
|
|
5
|
+
* useSchedule — run non-urgent work later, without blocking UI.
|
|
6
|
+
*/
|
|
7
|
+
export declare function useSchedule(options?: ScheduleOpts): (task: Task) => void;
|
|
8
|
+
/**
|
|
9
|
+
* useScheduledEffect — Runs a non-urgent task in a React component without blocking UI rendering.
|
|
10
|
+
*
|
|
11
|
+
* This hook is like `useEffect`, but the provided task is executed
|
|
12
|
+
* with low priority using `requestIdleCallback` (if available)
|
|
13
|
+
* or a fallback scheduler. Useful for heavy computations, logging,
|
|
14
|
+
* analytics, or background work that doesn't need to block render.
|
|
15
|
+
*
|
|
16
|
+
* @param {Task} task - The function to run later. Can be synchronous or return a Promise.
|
|
17
|
+
* @param {React.DependencyList[]} deps - Dependency array; task will re-run whenever these change.
|
|
18
|
+
* @param {ScheduleOpts} [options] - Optional scheduling options.
|
|
19
|
+
* @param {number} [options.timeout] - Max time (ms) to wait before executing the task. Defaults to 10000.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```tsx
|
|
23
|
+
* import React from 'react';
|
|
24
|
+
* import { useScheduledEffect } from './hooks/useScheduledEffect';
|
|
25
|
+
*
|
|
26
|
+
* function MyComponent({ userId }: { userId: string }) {
|
|
27
|
+
* useScheduledEffect(() => {
|
|
28
|
+
* // non-blocking analytics or heavy work
|
|
29
|
+
* console.log('Sending analytics for user:', userId);
|
|
30
|
+
* }, [userId], { timeout: 5000 });
|
|
31
|
+
*
|
|
32
|
+
* return <div>Component loaded. Task will run later 😎</div>;
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare function useScheduledEffect(task: Task, deps?: React.DependencyList, options?: ScheduleOpts): void;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { schedule as _schedule } from '../functions/schedule';
|
|
3
|
+
/**
|
|
4
|
+
* useSchedule — run non-urgent work later, without blocking UI.
|
|
5
|
+
*/
|
|
6
|
+
export function useSchedule(options = {}) {
|
|
7
|
+
const { timeout = 10000 } = options;
|
|
8
|
+
const schedule = React.useCallback((task) => {
|
|
9
|
+
const exec = () => {
|
|
10
|
+
try {
|
|
11
|
+
React.startTransition(() => {
|
|
12
|
+
task();
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
console.log('⚡[schedule.tsx] Failed: ', err);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
if ('requestIdleCallback' in window) {
|
|
20
|
+
requestIdleCallback(exec, { timeout });
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
_schedule(exec);
|
|
24
|
+
}
|
|
25
|
+
}, [timeout]);
|
|
26
|
+
return schedule;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* useScheduledEffect — Runs a non-urgent task in a React component without blocking UI rendering.
|
|
30
|
+
*
|
|
31
|
+
* This hook is like `useEffect`, but the provided task is executed
|
|
32
|
+
* with low priority using `requestIdleCallback` (if available)
|
|
33
|
+
* or a fallback scheduler. Useful for heavy computations, logging,
|
|
34
|
+
* analytics, or background work that doesn't need to block render.
|
|
35
|
+
*
|
|
36
|
+
* @param {Task} task - The function to run later. Can be synchronous or return a Promise.
|
|
37
|
+
* @param {React.DependencyList[]} deps - Dependency array; task will re-run whenever these change.
|
|
38
|
+
* @param {ScheduleOpts} [options] - Optional scheduling options.
|
|
39
|
+
* @param {number} [options.timeout] - Max time (ms) to wait before executing the task. Defaults to 10000.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```tsx
|
|
43
|
+
* import React from 'react';
|
|
44
|
+
* import { useScheduledEffect } from './hooks/useScheduledEffect';
|
|
45
|
+
*
|
|
46
|
+
* function MyComponent({ userId }: { userId: string }) {
|
|
47
|
+
* useScheduledEffect(() => {
|
|
48
|
+
* // non-blocking analytics or heavy work
|
|
49
|
+
* console.log('Sending analytics for user:', userId);
|
|
50
|
+
* }, [userId], { timeout: 5000 });
|
|
51
|
+
*
|
|
52
|
+
* return <div>Component loaded. Task will run later 😎</div>;
|
|
53
|
+
* }
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export function useScheduledEffect(task, deps = [], options = {}) {
|
|
57
|
+
const schedule = useSchedule(options);
|
|
58
|
+
React.useEffect(() => {
|
|
59
|
+
schedule(task);
|
|
60
|
+
}, [schedule, ...deps]);
|
|
61
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sohanemon/utils",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.2.0",
|
|
4
4
|
"author": "Sohan Emon <sohanemon@outlook.com>",
|
|
5
5
|
"description": "",
|
|
6
6
|
"type": "module",
|
|
@@ -44,14 +44,14 @@
|
|
|
44
44
|
],
|
|
45
45
|
"license": "ISC",
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@types/node": "^24.0
|
|
48
|
-
"@types/react": "^19.
|
|
49
|
-
"typescript": "^5.
|
|
47
|
+
"@types/node": "^24.10.0",
|
|
48
|
+
"@types/react": "^19.2.2",
|
|
49
|
+
"typescript": "^5.9.3"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@iconify/react": "^6.0.
|
|
52
|
+
"@iconify/react": "^6.0.2",
|
|
53
53
|
"clsx": "^2.1.1",
|
|
54
|
-
"react": "^19.
|
|
54
|
+
"react": "^19.2.0",
|
|
55
55
|
"tailwind-merge": "^3.3.1"
|
|
56
56
|
},
|
|
57
57
|
"packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977"
|