Skip to content

Instantly share code, notes, and snippets.

@maxfierke
Last active April 21, 2022 18:15
Show Gist options
  • Save maxfierke/5fb3708e4a41bc2a71700184915cbed9 to your computer and use it in GitHub Desktop.
Save maxfierke/5fb3708e4a41bc2a71700184915cbed9 to your computer and use it in GitHub Desktop.
cancelableFetch Yieldable ember-concurrency
import { Yieldable } from 'ember-concurrency';
import fetch from 'fetch'; // i.e. ember-fetch. could also use native fetch too.
class FetchYieldable extends Yieldable {
constructor(url, opts = {}) {
super(...arguments);
this.url = url;
this.opts = opts;
}
onYield(state) {
const controller = new AbortController();
const { signal } = controller;
let isComplete = false;
fetch(this.url, { ...this.opts, signal })
// eslint-disable-next-line promise/always-return
.then((response) => {
state.next(response);
isComplete = true;
})
.catch((err) => {
if (err instanceof DOMException && err.name === 'AbortError') {
return;
}
state.throw(err);
});
return () => {
if (!isComplete) {
// Aborting an already completed request with an as-yet unresolved Promise
// can cause an AbortError to be thrown which might get caught before
// the promise is resolved, so we should avoid that and never abort a
// request that we know has been completed.
controller.abort();
}
};
}
}
const cancelableFetch = (url, opts = {}) => new FetchYieldable(url, opts);
export default cancelableFetch;
import cancelableFetch from './cancelable-fetch';
class MyComponent extends Component {
@task({ drop: true })
*getSomething() {
const response = yield cancelableFetch("https://example.com", { Accept: "application/json" });
const json = yield response.json();
return json;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment