Skip to content

Commit

Permalink
Add support for AbortSignal (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
fregante committed Apr 3, 2024
1 parent 1c81997 commit 1fbdec5
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 7 deletions.
16 changes: 16 additions & 0 deletions index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,19 @@ test('should only listen to the specified mutations', async () => {
addedNodes: emptyNodeListFixture,
});
});

test('should stop observing when the signal is aborted', async () => {
const observer = oneMutation(document.body, {
signal: AbortSignal.timeout(10),
attributes: true,
});
t.deepEqual(await observer, []);
});

test('should resolve immediately if the signal is already aborted', async () => {
const observer = oneMutation(document.body, {
signal: AbortSignal.abort(),
attributes: true,
});
t.deepEqual(await observer, []);
});
18 changes: 14 additions & 4 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
type Options = {
filter?: (mutations: MutationRecord[]) => boolean;
signal?: AbortSignal;
} & MutationObserverInit;

export default async function oneMutation(
element: Element,
options: Options = {},
{filter, signal, ...options}: Options = {},
): Promise<MutationRecord[]> {
if (signal?.aborted) {
return [];
}

return new Promise(resolve => {
const {filter} = options;
new MutationObserver((changes, observer) => {
const observer = new MutationObserver(changes => {
if (!filter || filter(changes)) {
observer.disconnect();
resolve(changes);
}
}).observe(element, options);
});
observer.observe(element, options);

signal?.addEventListener('abort', () => {
observer.disconnect();
resolve([]);
});
});
}
25 changes: 22 additions & 3 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ new MutationObserver(callback).observe(NODE, options)

#### options

Type: `object` <br>
Type: `MutationObserverInit & {filter?: FilterFunction, signal?: AbortSignal}` <br>
Example: `{childList: true}`, `{subtree: true, filter: filterFunction}`

This matches [`MutationObserverInit`](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserverInit) and adds a `filter` method.
This matches [`MutationObserverInit`](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserverInit) and adds a `filter` method and an `signal` to cancel the observation.

The equivalent parameter of:

Expand All @@ -96,7 +96,7 @@ function filterFunction(mutations) {
}
}
}
```


A function that will be called every time that `MutationObserver` detects a change, the equivalent parameter of:

Expand All @@ -106,6 +106,25 @@ new MutationObserver(FILTER)

**But** it should only be used to return `true` or `false` so that the Promise can be resolved.

##### signal

Type: `AbortSignal` <br>
Example:

```js
const timeout = AbortSignal.timeout(1000);
oneMutation(document.body, {
signal: timeout,
attributes: true,
}).then(mutations => {
if (mutations.length > 0) {
console.log('No changes were detected in 1 second');
} else {
console.log('A change was detected!');
}
});
```

## Related

- [one-event](https://github.com/fregante/one-event) - Micro module to add an event listener to be executed only once.
Expand Down

0 comments on commit 1fbdec5

Please sign in to comment.