1.promise

In the traditional solution, js implements asynchronous programming with callback functions and event listeners (event published_subscribe), but when the application is complex and large, a large number of callbacks can make debugging difficult and a developer’s nightmare.

Promise is an ES6 standard solution for asynchronous programming. At the language level, unlike Java, Python and other multi-threaded languages, JS is single-threaded, so asynchronous programming techniques are heavily used in Node.js to avoid synchronous blocking.

A promise is to draw up a promise that returns a result when the promise is fulfilled, independent of other operations. It can be thought of as a simple container for the return result of an event that will end in the future (i.e. an asynchronous operation). Unlike traditional callbacks, the results of all asynchronous operations in a Promise are handled in a uniform way. Promises come in three states:

Pending, resolved, rejected, and the result of the asynchronous operation determines the current state. Promise can change only once and in two ways: From pending to resolved, from pending to Rejected, the result will remain the same.

The following code is a simple promise instance:

const promise = new Promise(function(resolve, reject){
//some code
if(/* Async operation succeeded */){resolve(value); }else{ reject(error); }});Copy the code

The Promise constructor takes a function as an argument, which is resolve and Reject. These are two functions. Once the Promise instance is generated, you can use the THEN method to specify the callbacks for Resolved and Rejected, respectively. The second function is optional. Here is a simple example of a Promise object:

function timeout(ms){
    return new Promise((resolve, reject) => {
    setTimeout(resolve, ms, "done");
    });
}

timeout(100).then((value) => {
    console.log(value);
});Copy the code

The timeout method returns an instance of a Promise that will not occur for a period of time. After that time, the Promise state changes to resolved, triggering the callback function bound to the THEN method.

let promise = new Promise(function(resolve, reject){
    console.log("Promise");
    resolve();
});

promise.then(function(){
    console.log("resolved.");
});
console.log("Hi!");
// Promise
// Hi!
// resolved.Copy the code

In the code above, Promise is created and executed immediately, so the Promise is returned first. Then, the callback function specified in the then method will not be executed until all synchronization tasks in the current script have been completed, so resolved output is finished.

This briefly describes the basic features of promises: once created, they are executed immediately; Three states: Executing, successful, failed; The result is not affected by other operations and cannot be cancelled. A Promise handles a single event when an asynchronous operation completes or fails.

2.Observable

Observable is an Observable. In many software programming tasks, you expect more or less the code you write to execute and complete in the order it was written, one at a time. But in ReactiveX (a library based on a series of observable asynchronous and underlying event programming), many instructions may be executed in parallel before their results are captured by observers in an indeterminable order. To do this, you define a mechanism to retrieve and transform data, rather than calling a method. In this mechanism, there is an Observable, an Observer subscribes to it, and when the data is ready, the previously defined mechanism dispatches the data to the Observer sentinel, which has been waiting.

ReactiveX visible mode allows you to use collections of data items such as arrays to perform some asynchronous event-stream combination operations. It frees you from tedious Web callbacks, making your code much more readable and less buggy.

  • Observable data is flexible; unlike promise, which can only handle a single value, Observalbe supports multiple values and even streams of data.
  • When the Observalbes is created, it is not immediately executed (lazy evaluation), and is only called when the results are really needed. For example, in the following code, a promise is executed whether or not a THEN is called; Observables, on the other hand, are created, not implemented, and are implemented only when results are needed, such as in the case of foreach.

var promise = new Promise((resolve) => {      setTimeout(() => {          resolve(42);      }, 500);      console.log("promise started");  });    //promise.then(x => console.log(x));    var source = Rx.Observable.create((observe) => {      setTimeout(() => {          observe.onNext(42);      }, 500);      console.log("observable started");  });    //source.forEach(x => console.log(x));  Copy the code

  • Observables can be disposed, or unsubscribed, before or during execution. In the example below, An Observable is disposed at 0.5 seconds, so the log “Observable Timeout hit” is not printed.

var promise = new Promise((resolve) => {      setTimeout(() => {          console.log("promise timeout hit")          resolve(42);      }, 1000);      console.log("promise started");  });    promise.then(x => console.log(x));    var source = Rx.Observable.create((observe) => {      id = setTimeout(() => {          console.log("observable timeout hit")          observe.onNext(42);      }, 1000);      console.log("observable started");        return () => {          console.log("dispose called"); clearTimeout(id); }}); var disposable = source.forEach(x => console.log(x));setTimeout(() => {      disposable.dispose();  }, 500);  Copy the code

  • Observables can be called multiple times, and the result returned by an Observable can be called multiple times, which can trigger multiple asynchronous operations. Many tool methods are encapsulated in the Observables to manipulate the Observable result and perform composite transformation on it. In the above code, you get the promise and Observable variables. For a promise, the actual asynchronous operation will only be performed once, no matter how then is called later. Multiple calls have no effect; But with An Observable, calling forEach multiple times or using the Retry method can trigger multiple asynchronous operations.

Here’s another angular2 instance scenario to see how promises and Observances differ in practice:

First, let’s define the scenario of the problem. Suppose we want to implement a search function, with a simple input box, when the user enters the text, the real-time query using the input text, and display the results of the query.

In this simple scenario, there are three questions to consider:

  • You cannot trigger a search every time the user enters each character. If the user enters every character to trigger the search, a waste of server resources, and the client frequently triggers the search, and update the search results, will also affect the client response. In general, this problem is avoided by adding some delay.
  • If the text entered by the user does not change, the search should not be re-searched. Suppose the user enters’ foo ‘, pauses, triggers a search, types another character ‘o’, finds a typo, and deletes the character. If the user pauses again, triggering a search, this time the text ‘foo’ is the same as the previous search, so it should not be searched again.
  • Consider the asynchronous return of the server. When sending multiple requests to the server asynchronously, we need to be aware that there is no guarantee of the order in which the requests will be returned. For example, we searched two words’ computer ‘and’ car ‘successively. Although the word’ car ‘was searched later, the server may process the search faster and return the result first. The search results for ‘car’ will be displayed first, and then the search results for ‘computer’ will be displayed when the search results for ‘computer’ are received. However, in this case, the user clearly searches for ‘car’, but shows a different result.


import { Injectable } from '@angular/core';
import { URLSearchParams, Jsonp } from '@angular/http';
@Injectable()
export class WikipediaService {  

constructor(private jsonp: Jsonp) {}  

search (term: string) {    
    var search = new URLSearchParams()    
    search.set('action'.'opensearch');    
    search.set('search', term);    
    search.set('format'.'json');    
    return this.jsonp                
    .get('http://en.wikipedia.org/w/api.php?callback=JSONP_CALLBACK', { search }) .toPromise() .then((response) => response.json()[1]); }}Copy the code

In the above code, we use the Jsonp module to request the API result. The result should be an Observable<Response> object. We convert the returned result from an Observable<Response> object to a Promise<Response> object. It then uses its THEN method to turn the result into JSON. Thus, the return type of the search method is Promise<Array<string>>. In this way, the query function is basically realized, but the three problems mentioned above are not solved.

Apply observable to implement this function:

(1) Control user input delay

exportclass AppComponent { items: Array<string>; term = new FormControl(); constructor(private wikipediaService: WikipediaService) { this.term.valueChanges .debounceTime(400) .subscribe(term => this.wikipediaService.search(term) .then(items => this.items = items)); }}Copy the code

Here this.term.valueChanges is an Observable

object, and we set the delay of its event firing to 400 milliseconds by debounceTime(400). Again, this method returns an Observable< String > object. We then add a subscription event to the object

subscribe(term => this.wikipediaService.search(term).then(items => this.items = items));Copy the code

This solves the first problem by controlling the user input delay to trigger a search each time a character is typed.

(2) Prevent triggering twice

this.term.valueChanges           .debounceTime(400)           .distinctUntilChanged()           .subscribe(term => this.wikipediaService.search(term).then(items => this.items = items));Copy the code

The above code solves the second problem, which is that after a 400ms delay, the user enters the same search criteria. Observable has a method, distinctUntilChanged, that determines whether the new data from the message source is consistent with the last one, and triggers the subscription only if it is not.

(3) Processing return order

The above describes a problem that occurs when the server returns data asynchronously and the return order is inconsistent. Our solution to this problem is straightforward, which is to ignore the results of previous requests and only process the results of the last user request on the page. This can be solved by using the Dispose () method of Observable. Instead of calling the Dispose () method directly, we use the ‘disposable’ feature. (” Disposable “means THAT I can stop the processing of messages on Observable, which literally means disposable.)

search (term: string) {
  var search = new URLSearchParams()
  search.set('action'.'opensearch');
  search.set('search', term);
  search.set('format'.'json');
  return this.jsonp             
 .get('http://en.wikipedia.org/w/api.php?callback=JSONP_CALLBACK', { search })              
 .map((response) => response.json()[1]);
}Copy the code

Map ((response) => Response.json ()[1]), which translates the original response result into a list of actual search results, using the Observable feature to discard the last result that was not returned in time.

Conclusion: Observable is preferred over Promise for some complex asynchronous applications because asynchronous tasks created using Observable can be processed and loaded delayingly. While Promises were designed to solve the debugging problem caused by the large number of asynchronous callbacks, Observable encapsulates a number of methods that we can use to handle complex asynchronous tasks.

Some of the above is from Yipeng Ruan’s Introduction to ES6, the difference between a Promise and an Observable, and a good video: this 7-minute video on Egghead. IO by Ben Lesh. It is the first time to write an article on the gold, is a summary of personal knowledge, it is inevitable that there will be mistakes and omissions, welcome to give advice.