Understanding Observable, Promise, and Callback

Callbacks

A callback is that you register a piece of code (almost always a function) that will run when an event occurs.

1
2
3
4
5
6
7
8

<button onclick="myFunction()">Click me.</button>
<p id="demo"></p>
<script>
function myFunction() {
document.getElementById("demo").innerHTML = "YOU CLICKED ME!";
}
</script>

This is an example of registering a callback. In this case onclick="myFunction()" is registering a callback with the function myFunction()

Promises

A promise is an Object that will call you back when it has something to give you. You need to register a callback that will be called when the Promise is ready to deliver its goods.

When Promise is done doing its thing (fetching data, counting…), it calles the callback function that was defined.

When we are using the Promise, actually we are defining argument to then(). When we define callback functions for a Promise, we can define up to 3 functions, one called when the Promise is resolved, one called when the Promise is rejected, and another one when the Promise has error.

Use Promise

Ionic Storage returns a Promise when use .get(key).

1
2
3
4
let myData: any;
storage.get('myKey').then(theDataStoredWithMyKey => {
myData = theDataStoredWithMyKey;
}

Promise.then() is doing two things when you call it:

  • Registering a callback
  • Signaling to the Promise that it should start doing its work
  • Consumer calls Promise.then() => Promise run function defined in itself => call resolve() if function success => Run callback functions defined in .then(), the callback should take one parameter: the result
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Promise Provider
function getData() {
return new Promise(
//pass a function to the constructor
// the function should take 2 parameters
(resolve, rejected) => {
let data = getDataFromCache();
if ( data === undefined) {
data = getDataFromWeb();
}
// when the work is done, call resolve()
resolve(data); // pass the data out
}
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Promise Consumer
let dataWant: any;
thePromise = myService.getData();
thePromise.then(
// pass the callback function as a parameter
// it should take one parameter: the result
(dataFromService) => {
dataWant = dataFromService;
}
)

// OR USE Async & await function
async function getData() {
const dataWant = await dataFromService;
console.log(dataWant);
}
getData();

Good to Know

  • Most Promises are used when a function call could take a long time.
  • How to use Promise as Consumer is more important
  • Async function always returns a Promise with resolved value of return value.

Observables

Difference between Promise and Observables:

  • A Promise does its work only once. When the consumer calls the .then(), the Promise’s would execute and done
  • An Observable keeps working. It returns a stream of results, rather than just a single result. A consumer, instead of calling .then(), calls .subscribe(). The Consumer defines a callback function that will run whenever the Observable has results to share.
  • The callback function will run whenever the Observable is updated

.map() TBA

Creating Observable

A good use case for Observables is anytime that you have some data that could be updated by different part of your app and you want to be able to notify the other parts of the app that the data has changed.

Observer

Observer is the piece of code that observes some data and makes that data observable by notifying subscribers of changes. The Observer provides Observables to subscribers, and uses those Observables as the communication channel by which to notify them of changes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

export class HeroesService {
private theObservable: Observable<Object>;
private theObserver: Observer<Object>;

...

public getObservable(): Observable<Object> {
if (this.theObservable === undefined) {
this.theObservable = Observable.create(
observer =>
this.theObserver = observer);
}
return this.theObservable;
}
...

private updateSubscribers() {
if (this.theObserver) {
this.theObserver.next(true);
}
}

// Decide when to notify subscribers
public saveData(): void {
this.heroBundle = this.heroManager.getHeroes();
this.storage.set(this.DATA_KEY, this.heroBundle);
this.updateSubscribers();
}

}

At Runtime:

  1. The Consumer calls a function (e.g. getObservable()) that returns an Observable
  2. Inside that function, the Provider creates the Observable (Observable.create()), and in the process obtains an Observer that is linked to the Observable that is returned. This linkage happens inside the Observable.create().
  3. Once the Consumer has a handle to the Observable, it calls subscribe(callbackFunction).
1
2
3
4
5
6
obs = HeroesService.getObservable();
obs.subscribe(
result => {
// code do something with the result
}
)
  1. At this point nothing actually happens. All that has happened is the Consumer has registered itself with the Observable as “interested”, but the Consumer’s callback function won’t actually get called until the Observable has a result.
  2. When the Observer has a result, it calls myObserver.next(result). It automatically “notifies” all of the Consumers who have subscribed to the linked Observable of the result by calling the callback function that was registered when they registered.
  3. As the Observer has more result, the Consumer’s callback function is called again with the new result.

AJAX and APIs

AJAX (Asynchronous Javascript And Xml)

crossorigin.me to solve CORS problem

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fetch('URL/api/')
.then(
result => {
console.log(result);
return result.json();
}
)
.then(
data => {
console.log(data);
}
)
.catch(
error => console.log(error)
)