Comments (9)
Thanks for the ping. I think I did see that recently, yes. Very glad to see it happening.
The thing that comes to mind first is the need to be able to easily get a promise that resolves (or rejects!) when an a specific abort token is triggered.
CAF implements this as a .pr
property on the signal
object, so you can "subscribe" to that. But it would be nice if there was some idiomatic and clean way to take a signal
and get a Promise for its firing.
Do you have any thoughts on that?
from caf.
Also, more broadly, I'd like to see more (ideally, all someday) of Node's asynchronous APIs taking the signal
as a param, similar to fetch(..)
and addEventListener(..)
in the web, to force deep cancellation of any async tasks.
For example:
fs.writeFile("/path/to/file.txt", someBigContents, { encoding: "utf-8", signal });
One place that might be easy to start in terms of rolling out that support might be the Timers APIs, for example:
setTimeout(
function whatever() {
// ..
},
{
delay: 2000,
signal
}
);
from caf.
if we can show a compelling enough use case for it (I think it's probably doable).
As for "compelling use case", basically I do this (via CAF) almost all the time:
Promise.race([
// some work
// abort signal promise
])
from caf.
I've opened a post regarding aborted
- in the meantime I'll try to push (internal) weak event handlers in (so that aborted
does not leak memory and holds the callback "weakly" on the object).
from caf.
Thanks for the detailed answer and feedback!
The thing that comes to mind first is the need to be able to easily get a promise that resolves (or rejects!) when an a specific abort token is triggered.
CAF implements this as a .pr property on the signal object, so you can "subscribe" to that. But it would be nice if there was some idiomatic and clean way to take a signal and get a Promise for its firing.
Do you have any thoughts on that?
Unfortunately I don't think we are allowed (spec wise) to add methods to AbortSignal
.
We do have a utility in events
that makes this easier:
const { once } = require('events');
const ac = new AbortController();
const { signal } = ac;
// some time later, we want to wait for the signal to abort
await once(signal, 'abort'); // Works with both EventTarget and EventEmitter, fulfills with `undefined` once the event fired
One possible downside for this is that it doesn't fire if the signal already fired so the actual code would have to look like:
await (signal.aborted || once(signal, 'abort'));
Which might not be the most intuitive to users so the ergonomics do leave room for improvement.
I have collaborated with whatwg before on related modifications (adding AbortSignal support to EventTarget for example) so I think adding .aborted
Promise (or similar) to AbortSignal should be possible if we can show a compelling enough use case for it (I think it's probably doable).
Additionally we can (should we?) expose a utility for this in Node.js (we are allowed to do that without violating the spec). It can look something like:
await aborted(signal); // fulfills the promise when the signal fires `abort` (or immediately if it is already aborted
(As a fun tidbit - once
actually takes a signal third parameter itself to allow cancelling waiting for the event)
Also, more broadly, I'd like to see more (ideally, all someday) of Node's asynchronous APIs taking the signal as a param, similar to fetch(..) and addEventListener(..) in the web, to force deep cancellation of any async tasks.
I am very much in favour!
We have been rapidly adding support for AbortSignal
s in core APIs in recent versions (15.3+). I am happy to say your fs.writeFile
example already works today on the latest v15 release 😄 .
This is also true for the promises version of fs.writeFile
. We are at a point where most APIs are covered:
stream
- all readable and writeable streams take a signal parameter in their constructor to destroy the stream. An additionaladdAbortSignal
utility method is exposed to enable use-cases where you don't control stream construction.fs
-readFile
,writeFile
as well as anything with streams likefs.createReadStream
, there are open PRs forfs.watch
and the promises version.http
- requests usinghttp.request
take an AbortSignal parameter.http2
- requests usinghttp2.request
take an AbortSignal parameter.events
- theevents.on
and
events.once` methods take an AbortSignal parameter.net
- it is possible to stop anet.Server
with an AbortSignal.dgram
- it is possible to stop audp.createSocket
with an AbortSignal.
One place that might be easy to start in terms of rolling out that support might be the Timers APIs, for example:
Also happy to tell you that this already works (with setInterval landing less than 6 hours ago 🎉 ):
import { setInterval, setTimeout /*, setImmediate*/ } from 'timers/promises'; // with "type": "module"
// const { setInterval, setTimeout, setImmediate } = require('timers/promises');
const ac = new AbortController();
const { signal } = ac;
setTimeout(500).then(() => ac.abort());
(async () => { // setInterval example
for await (const tick of setInterval(100, null, { signal })) {
console.log("interval ping")
}
})();
(async () => { // setTimeout example
console.log('before setTimeout');
try {
await setTimeout(1000, null, { signal });
console.log('timeout elapsed');
} catch (e) {
console.log('got an:', e.name);
}
console.log('after setTimeout');
})();
// Logs
// before setTimeout
// interval ping
// interval ping
// interval ping
// interval got an: AbortError
// timeout got an: AbortError
// after setTimeout
Interesting times :]
from caf.
Hmm... question about the timers thing... it's passed as the third parameter? In the web, setTimeout/setInterval take optional third (and further) params and pass them as arguments to the callback. Does that break here?
from caf.
@getify it does break here - but whatwg seemed optimistic regarding adding a (future) new promises-based API and even said (and I quote):
For Chrome/V8, I can say that we're not interested in any version without AbortSignal integration, or any version that does not use the same specification infrastructure as setTimeout.
So it seems like if (when) a promises version of setTimeout will reach the DOM it'll have AbortSignal support and no collision with the "regular" setTimeout
(either with an import or with another name).
That said: Node timers and Web timers don't implement the same specification (or rather - Node timers don't follow the specification and return objects and not numbers) anyway :]
(The main reason that the web timers promises version hasn't progressed is people dedicating time to working on it, I am pretty confident that if the spec was written and agreed on - browsers would implement)
from caf.
Ahhh... I hadn't looked at Node's "timers/promises" before. Yeah, the signature is different: since there's no callback there's no need to pass args. And instead, there's just a single value
argument to resolve the promise with. Makes more sense.
from caf.
I like this a lot. This would be great if Node could consider adding it:
await aborted(signal);
The name aborted
is pretty generic and likely to cause lexical conflicts. Wondering what we can do to make it easy to use but not likely to collide lexically.
from caf.
Related Issues (20)
- Only catch canceled promise HOT 2
- Can't use with create-react-app HOT 28
- Implementing debounce with CAF? HOT 11
- What happens to cancelled generator functions? No leaks? HOT 2
- How to use CAF with Axios' `cancelToken` argument? HOT 5
- Feature request: configurable 'this' context HOT 3
- Unexpected try/catch/finally semantics HOT 11
- Switch cancelToken to AbortSignal HOT 10
- Possible improvement to memory cleanup in signal race/all combinators HOT 1
- How can I dynamically detect a CAF-wrapped generator? HOT 4
- ReferenceError: AbortController is not defined HOT 8
- Import Problems — TypeError: (0 , _caf.CAF) is not a function HOT 9
- AbortController not defined using ES Import statements HOT 1
- Cannot set property reason of #<AbortSignal> which has only a getter HOT 6
- Improve error when `signal` isn't passed down correctly to a sub-CAF HOT 1
- explore: should CAF support "async generators"? HOT 2
- Typescript typings file :) HOT 6
- update "abortcontroller" to fully use new version of polyfill
- add `signalRace(..)` and `signalAll(..)` helpers
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from caf.