Created
October 14, 2024 01:14
-
-
Save dmorosinotto/a88c96b7dfe1c570dd8964db24c46f1b to your computer and use it in GitHub Desktop.
PromiseEX - Extends Promise with $status Signal + cancel: AbortSignal controller
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { signal } from "@angular/core"; | |
import type { Signal, WritableSignal } from "@angular/core"; | |
export type PromiseStatus<T> = PromiseSettledResult<T> | { status: "pending" }; | |
export interface PromiseEx<T> extends Promise<T>, Disposable, AsyncDisposable { | |
$status: Signal<PromiseStatus<T>>; | |
cancel: AbortSignal; | |
abort: AbortController["abort"]; | |
} | |
export class PromiseEx<T> extends Promise<T> implements PromiseEx<T> { | |
constructor(p: Promise<T>) { | |
let abort: (reason?: any) => void; | |
super((resolve, reject) => { | |
abort = reject; | |
resolve(p); | |
}); | |
this.$status = signal({ status: "pending" }); | |
const ctrl = new AbortController(); | |
this.cancel = ctrl.signal; | |
this.abort = ctrl.abort; | |
this.cancel.addEventListener("abort", () => { | |
console.error("-X- ADESSO ABORT", this.cancel.reason); | |
abort(this.cancel.reason); // reject the promise | |
}); | |
console.log("|-- ADESSO INIT $status", JSON.stringify(this.$status())); | |
Promise.allSettled([p]).then(([status]) => { | |
console.log("--> ADESSO SET $status", JSON.stringify(status)); | |
(this.$status as WritableSignal<PromiseStatus<T>>).set(status); | |
}); | |
} | |
[Symbol.dispose](reason?: any) { | |
this.abort(reason); // ALLOW using SINTAX | |
} | |
async [Symbol.asyncDispose]() { | |
this.abort(); // ALLOW await using SINTAX | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Component, computed, effect, signal, inject } from "@angular/core"; | |
import type { Signal, WritableSignal } from "@angular/core"; | |
import { AsyncPipe, JsonPipe } from "@angular/common"; | |
import { FakeApiService } from "../fake-api.service"; | |
import { interval, take } from "rxjs"; | |
import { toSignal } from "@angular/core/rxjs-interop"; | |
@Component({ | |
selector: "sample", | |
standalone: true, | |
imports: [AsyncPipe, JsonPipe], | |
template: ` | |
@let res = $data() | async; | |
<h3>Data: {{ res }}</h3> | |
<pre>{{ $status() | json }}</pre> | |
@if (!$isPending()) { | |
<button (click)="change()">Next</button> | |
} | |
`, | |
}) | |
export default class HomeComponent { | |
api = inject(FakeApiService); | |
$id = signal(1); | |
$data = computed(() => new PromiseEx(this.api.getById(this.$id()))); // $id() is a signal | |
$timer = toSignal(interval(1000).pipe(take(15)), { initialValue: 0 }); | |
$status = computed(() => this.$data().$status()); | |
$isPending = computed(() => this.$data().$status().status === "pending"); | |
async init() { | |
console.clear(); | |
console.log("START TEST SIGNAL"); | |
after().then(this.change); | |
console.log("PRE isPending:", this.$isPending()); | |
console.log("PRE status:", this.$data().$status().status); | |
console.log("HERE:", await this.$data()); | |
after(2).then((_) => { | |
console.log("POST status:", this.$data().$status().status); | |
console.log("POST isPensing:", this.$isPending()); | |
}); | |
after(10).then(this.change); | |
} | |
change = () => { | |
console.error("change ++$id"); | |
this.$id.update((n) => n + 1); | |
}; | |
constructor() { | |
this.init(); | |
effect(() => { | |
console.log("EFFECT id:", this.$id()); | |
console.error("id change -> START REALOAING DATA!"); | |
}); | |
effect(async () => { | |
console.log("ASYNC EFFET"); | |
const res = await this.$data(); | |
const status = this.$data().$status(); | |
const pending = this.$isPending(); | |
console.warn("EFFECT res:", res, pending, status); | |
}); | |
effect(async () => { | |
const status = this.$data().$status(); | |
const pending = this.$isPending(); | |
console.warn("$$$", pending, JSON.stringify(status)); | |
}); | |
effect(() => { | |
console.info(`...${this.$timer()}s`); | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment