In the endless quest to get asynchronous operations right, we're constantly changing approaches. From callbacks, to promises, to awaits, to observables. Observables are pretty straight forward: we observe something, like a socket or a HTTP request, and when something happens, we trigger some callbacks. In a lightly pseudocode version, it might look something like:
requestFactory.postFormRequest(url).subscribe(
resp => myResponseHandler(resp),
err => myErrorHandler(err),
() => myRequestCompleteHandler()
)
It's cleaner than pure callback hell, but conceptually similar. The key advantage to observables is that they work exactly the same way on objects that may emit multiple events, like a WebSocket. Each time a message arrives on the socket, we can simply re-execute the handlers for our subscription.
I lay out this background, because Lucas has a co-worker who doesn't quite get it. Because every time they need to make a request, they follow this pattern:
return new Observable<ILeaseFile>(observer => {
this._request.new_postForm<ILeaseFile>(this._app.apiUrl() + requestUrl + paramsUrl, formData).subscribe(
leaseFileRes => observer.next(leaseFileRes),
error => observer.error(error),
() => observer.complete()
);
});
This creates two observables. The first, created by this bit, this._request.new_postForm<ILeaseFile>(this._app.apiUrl() + requestUrl + paramsUrl, formData)
, is a request factory. It creates a request, adds some error handling code- code which uses window.alert
to raise errors- and returns an observable.
In this code example, we create a second outer observable, which is what subscribes to the request- the observer.next
, observer.error
, and observer.complete
do those steps. So the outer observable is just a do-nothing observer.
Why? I'll let Lucas explain:
The reason for this is that, sometimes, it wants to return a particular field from the response, and not all of it, and it was then copy-pasted all over. Or maybe someone doesn't understand asynchronous requests. Probably both.