-
-
Save alvarotf/95ba4ad6355be50d28b338d51dec1683 to your computer and use it in GitHub Desktop.
import { Injectable } from '@angular/core'; | |
import { Observable, Observer, Subscription } from 'rxjs'; | |
@Injectable({ | |
providedIn: 'root' | |
}) | |
export class AsyncApiCallHelperService { | |
taskProcessor: MyAsyncTaskProcessor; | |
constructor() { | |
this.taskProcessor = new MyAsyncTaskProcessor(); | |
} | |
doTask<T>(promise: Promise<T>) { | |
return <Observable<T>> this.taskProcessor.doTask(promise); | |
} | |
} | |
declare const Zone: any; | |
export abstract class ZoneMacroTaskWrapper<S, R> { | |
wrap(request: S): Observable<R> { | |
return new Observable((observer: Observer<R>) => { | |
let task; | |
let scheduled = false; | |
let sub: Subscription|null = null; | |
let savedResult: any = null; | |
let savedError: any = null; | |
// tslint:disable-next-line:no-shadowed-variable | |
const scheduleTask = (_task: any) => { | |
task = _task; | |
scheduled = true; | |
const delegate = this.delegate(request); | |
sub = delegate.subscribe( | |
res => savedResult = res, | |
err => { | |
if (!scheduled) { | |
throw new Error( | |
'An http observable was completed twice. This shouldn\'t happen, please file a bug.'); | |
} | |
savedError = err; | |
scheduled = false; | |
task.invoke(); | |
}, | |
() => { | |
if (!scheduled) { | |
throw new Error( | |
'An http observable was completed twice. This shouldn\'t happen, please file a bug.'); | |
} | |
scheduled = false; | |
task.invoke(); | |
}); | |
}; | |
// tslint:disable-next-line:no-shadowed-variable | |
const cancelTask = (_task: any) => { | |
if (!scheduled) { | |
return; | |
} | |
scheduled = false; | |
if (sub) { | |
sub.unsubscribe(); | |
sub = null; | |
} | |
}; | |
const onComplete = () => { | |
if (savedError !== null) { | |
observer.error(savedError); | |
} else { | |
observer.next(savedResult); | |
observer.complete(); | |
} | |
}; | |
// MockBackend for Http is synchronous, which means that if scheduleTask is by | |
// scheduleMacroTask, the request will hit MockBackend and the response will be | |
// sent, causing task.invoke() to be called. | |
const _task = Zone.current.scheduleMacroTask( | |
'ZoneMacroTaskWrapper.subscribe', onComplete, {}, () => null, cancelTask); | |
scheduleTask(_task); | |
return () => { | |
if (scheduled && task) { | |
task.zone.cancelTask(task); | |
scheduled = false; | |
} | |
if (sub) { | |
sub.unsubscribe(); | |
sub = null; | |
} | |
}; | |
}); | |
} | |
protected abstract delegate(request: S): Observable<R>; | |
} | |
export class MyAsyncTaskProcessor extends | |
ZoneMacroTaskWrapper<Promise<any>, any> { | |
constructor() { super(); } | |
// your public task invocation method signature | |
doTask(request: Promise<any>): Observable<any> { | |
// call via ZoneMacroTaskWrapper | |
return this.wrap(request); | |
} | |
// delegated raw implementation that will be called by ZoneMacroTaskWrapper | |
protected delegate(request: Promise<any>): Observable<any> { | |
return new Observable<any>((observer: Observer<any>) => { | |
// calling observer.next / complete / error | |
request | |
.then(result => { | |
observer.next(result); | |
observer.complete(); | |
}).catch(error => observer.error(error)); | |
}); | |
} | |
} |
Hi Guys is there another way to implement this? I'm already using something like:
/**
* read
*
* @param id
* @return
*/
public read(id: string): Observable<T> {
return this.httpClient
.get(`${this.url}/${this.endpoint}/${id}`)
.pipe(map((data: any) => this.serializer.fromJson(data) as T));
}
Thats will difficult my implementation..
It works however, I could see a long deal in loading and sometimes the page time out.
Tks, you saved my day!
Maybe this will work
public read(id: string): Observable<T> {
return this.processor
.doTask(this.httpClient
.get(`${this.url}/${this.endpoint}/${id}`)
.pipe(map((data: any) => this.serializer.fromJson(data) as T)));
}
Assuming that AsyncApiCallHelperService
has been injected as processor
into the constructor.
Hi all,
We have just migrated to Angular 9 and it seems the MyAsyncTaskProcessor implementation does not work anymore: we are facing timeout error. It's like the task is always pending and for our SSR implementation, it means our page is never rendered (or to be accurate, the page is rendered after 60 seconds).
We are using the exact same code when testing Angular 8 and Angular 9.
Has anyone of you already faced this issue after the migration to Angular 9 (or Angular 10)?
@heavenchains
from this:
to this:
this.processor
is theMyAsyncTaskProcessor
injected service.