deferExecution() in Refine source code.
In this article, we will review a function named deferExecution() in Refine source code.
/**
* Delays the execution of a callback function asynchronously.
* This utility function is used to defer the execution of the provided
* callback, allowing the current call stack to clear before the callback
* is invoked. It is particularly useful for ensuring non-blocking behavior
* and providing a clear intent when a 0 ms timeout is used.
*/
export const deferExecution = (fn: Function) => {
setTimeout(fn, 0);
};
This above code snippet is picked from refinedev/refine/packages/core/src/definitions/helpers/defer-execution/index.ts
This code is inside a folder named defer-execution. It contains the files shown in the below image.
so what is deferExecution used for?
/**
Delays the execution of a callback function asynchronously. This utility function is used to defer the execution of the provided
callback, allowing the current call stack to clear before the callback is invoked. It is particularly useful for ensuring non-blocking behavior
and providing a clear intent when a 0 ms timeout is used. /
This comment above the function explains clearly what this function is about.
The time, in milliseconds that the timer should wait before the specified function or code is executed. If this parameter is omitted, a value of 0 is used, meaning execute “immediately”, or more accurately, the next event cycle. Read more about setTimeout.
Wait, what is event cycle? For that, you need to read about Job queue and event loop in JavaScript Execution Model documentation
A job is considered completed when the stack is empty; then, the next job is pulled from the queue. Jobs might not be pulled with uniform priority — for example, HTML event loops split jobs into two categories: tasks and microtasks. Microtasks have higher priority and the microtask queue is drained first before the task queue is pulled.
Okay, at this point, let’s go find out how this deferExecution is used in the Refine codebase.
deferExecution usage
if (!isPessimistic && !isAutosave) {
// If the mutation mode is not pessimistic, handle the redirect immediately in an async manner
// `setWarnWhen` blocks the redirects until set to `false`
// If redirect is done before the value is properly set, it will be blocked.
// We're deferring the execution of the redirect to ensure that the value is set properly.
deferExecution(() => onSuccessRedirect());
// Resolve the promise immediately
resolve();
}
This code snippet is one instance picked from hooks/form/index.ts
But I am surprised there is no clean up in the sense that timeout is not cleared
Testing deferExecution()
You will find a file named defer-execution/index.spec.ts containing the below code:
import { waitFor } from "@testing-library/react";
import { deferExecution } from ".";
describe("deferExecution", () => {
beforeEach(() => {
jest.useRealTimers();
});
afterEach(() => {
jest.useFakeTimers();
});
it("should defer the call after caller returns", async () => {
const array: number[] = [];
const fn = () => {
array.push(1);
deferExecution(() => {
array.push(3);
});
array.push(2);
};
fn();
await waitFor(() => {
expect(array).toEqual([1, 2, 3]);
});
});
});
arr.push(3) is called inside deferExecution and the result is validated to [1, 2, 3].
About me:
Hey, my name is Ramu Narasinga. I study large open-source projects and create content about their codebase architecture and best practices, sharing it through articles, videos.
I am open to work on interesting projects. Send me an email at ramu.narasinga@gmail.com
My Github — https://github.com/ramu-narasinga
My website — https://ramunarasinga.com
My Youtube channel — https://www.youtube.com/@thinkthroo
Learning platform — https://thinkthroo.com
Codebase Architecture — https://app.thinkthroo.com/architecture
Best practices — https://app.thinkthroo.com/best-practices
Production-grade projects — https://app.thinkthroo.com/production-grade-projects