-
-
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)); | |
}); | |
} | |
} |
@heavenchains
from this:
async get(
url: string,
query?: any,
option?: AxiosRequestConfig
): Promise<ResponseResult> {
return await this.handleRequest(Methods.GET, url, null, query, option);
}
to this:
async get(
url: string,
query?: any,
option?: AxiosRequestConfig
): Promise<ResponseResult> {
return new Promise<ResponseResult>(resolve => {
this.processor
.doTask(this.handleRequest(Methods.GET, url, null, query, option))
.subscribe(result => {
resolve(result);
});
});
}
this.processor
is the MyAsyncTaskProcessor
injected service.
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)?
Hey could you please tell me how does it work and how do I inject it into my application and use it? thanks