A controller for Lit that renders asynchronous tasks.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Argument comparison utilities for controlling when tasks should re-execute based on changes to their input parameters.
Default equality function that performs shallow comparison of argument arrays.
/**
* Compares two argument arrays for shallow equality
* Uses notEqual from @lit/reactive-element for individual item comparison
* @param oldArgs - Previous arguments array
* @param newArgs - Current arguments array
* @returns true if arrays have same length and all items are shallowly equal
*/
function shallowArrayEquals<T extends ReadonlyArray<unknown>>(
oldArgs: T,
newArgs: T
): boolean;Usage Examples:
import { Task, shallowArrayEquals } from "@lit/task";
class MyElement extends LitElement {
// Default behavior (shallowArrayEquals is used automatically)
private _basicTask = new Task(this, {
task: async ([name, age]) => fetchUserData(name, age),
args: () => [this.userName, this.userAge]
// argsEqual defaults to shallowArrayEquals
});
// Explicit shallow comparison
private _explicitTask = new Task(this, {
task: async ([id, settings]) => updateUser(id, settings),
args: () => [this.userId, this.userSettings],
argsEqual: shallowArrayEquals
});
}Advanced equality function that performs deep comparison of argument arrays, useful when arguments contain objects.
/**
* Compares two argument arrays for deep equality
* Recursively compares nested objects, arrays, and primitive values
* @param oldArgs - Previous arguments array
* @param newArgs - Current arguments array
* @returns true if arrays and all nested content are deeply equal
*/
function deepArrayEquals<T extends ReadonlyArray<unknown>>(
oldArgs: T,
newArgs: T
): boolean;Usage Examples:
import { Task } from "@lit/task";
import { deepArrayEquals } from "@lit/task/deep-equals.js";
class DataComponent extends LitElement {
private _complexTask = new Task(this, {
task: async ([filters, options]) => {
return searchData(filters, options);
},
args: () => [
{ category: this.category, tags: this.selectedTags },
{ sortBy: this.sortField, ascending: this.sortAsc }
],
// Use deep equality since arguments are objects
argsEqual: deepArrayEquals
});
updateFilters(newCategory: string, newTags: string[]) {
this.category = newCategory;
this.selectedTags = [...newTags];
// Task will re-run because deepArrayEquals detects the change
}
}Core deep equality function for comparing individual values recursively.
/**
* Recursively compares two values for deep equality
* Handles primitives, objects, arrays, Maps, Sets, RegExps, and custom valueOf/toString
* @param a - First value to compare
* @param b - Second value to compare
* @returns true if values are deeply equal
*/
function deepEquals(a: unknown, b: unknown): boolean;Supported Types:
Usage Examples:
import { deepEquals } from "@lit/task/deep-equals.js";
// Custom equality function using deepEquals
class CustomComponent extends LitElement {
private _advancedTask = new Task(this, {
task: async ([config]) => processConfig(config),
args: () => [this.configuration],
argsEqual: (oldArgs, newArgs) => {
// Custom logic: only check the 'important' field deeply
return deepEquals(oldArgs[0]?.important, newArgs[0]?.important);
}
});
}
// Testing equality manually
const config1 = {
settings: { theme: 'dark', lang: 'en' },
metadata: new Date('2023-01-01')
};
const config2 = {
settings: { theme: 'dark', lang: 'en' },
metadata: new Date('2023-01-01')
};
console.log(deepEquals(config1, config2)); // trueCreating custom argument comparison functions for specific use cases.
Performance-Optimized Equality:
class OptimizedComponent extends LitElement {
private _optimizedTask = new Task(this, {
task: async ([userId, prefs]) => loadUserPreferences(userId, prefs),
args: () => [this.userId, this.userPreferences],
// Only check userId, ignore preferences changes
argsEqual: (oldArgs, newArgs) => oldArgs[0] === newArgs[0]
});
}Selective Deep Comparison:
class SelectiveComponent extends LitElement {
private _selectiveTask = new Task(this, {
task: async ([query, filters, pagination]) => searchAPI(query, filters, pagination),
args: () => [this.searchQuery, this.activeFilters, this.paginationState],
argsEqual: (oldArgs, newArgs) => {
// Shallow check query and deep check filters, ignore pagination
return oldArgs[0] === newArgs[0] &&
deepEquals(oldArgs[1], newArgs[1]);
}
});
}Debounced Equality:
class DebouncedComponent extends LitElement {
private _lastChangeTime = 0;
private _debounceMs = 300;
private _debouncedTask = new Task(this, {
task: async ([searchTerm]) => searchAPI(searchTerm),
args: () => [this.searchInput],
argsEqual: (oldArgs, newArgs) => {
const now = Date.now();
if (oldArgs[0] !== newArgs[0]) {
this._lastChangeTime = now;
return true; // Consider equal to prevent immediate execution
}
// Only execute if enough time has passed
return (now - this._lastChangeTime) < this._debounceMs;
}
});
}Cycle Detection:
The deepEquals function does not handle circular references. Objects must be cycle-free or the function will run infinitely.
Performance Considerations:
shallowArrayEquals: Fast, suitable for primitive argumentsdeepArrayEquals: Slower, use when arguments contain objectsType Safety: All equality functions maintain full TypeScript type safety with the argument arrays.