Promise basics

Promise basics

Read the information promise mini book We have a problem with promises (Chinese version see here) to resolve the race conditions when using Promises. Teacher Ruan's jQuery deferred object detailed explanation

Solve the problem of asynchronous processing, the traditional method is to use a callback function

What is the difference between this and the callback function method? When using promises for one-step processing, we must write processing code in accordance with the method specified by the interface. In other words, methods other than the methods specified by the promise object (then or catch here) cannot be used, and the parameters of the callback function cannot be defined freely like the callback function method, but must be strictly adhered to. , A unified programming method to write code. In this way, the unified interface based on Promise can form various asynchronous processing modes based on the interface. Therefore, the function of promises is to easily model complex asynchronous processing, which can also be said to be one of the reasons for using promises.

Basic usage of Promise

function getURL(url) {
    return new Promise(function (resolve, reject) {
        var xhr = new XMLHttpRequest();
        xhr.open('get', url, true);

        xhr.onload = function () {
            if (xhr.status === 200) {
                resolve(xhr.responseText);
            }
            else {
                reject(new Error(xhr.statusText));
            }
        };
        xhr.onerror = function () {
            reject(new Error(xhr.statusText));
        };

        xhr.send();
    });
}

getURL("xxx").then(function (responseText) {
    console.log(responseText);
}).catch(function (error) {
    console.error(error);
});

The static method Promise.resolve(value) can be considered as a shortcut to the new Promise() method. Will make this promise object immediately enter the determined (resolved) state, but what if there are other asynchronous operations?

Promise.resolve(thenable object) then converts the thenable object into a promise object and returns

var promise = Promise.resolve($.ajax('/json/comment.json'));//=> promise object
promise.then(function(value){
   console.log(value);
});

In order to avoid the confusion that may be caused by using synchronous and asynchronous calls at the same time, Promise stipulates that the then of Promise can only use asynchronous calls in the specification.

var promise = new Promise(function (resolve){
    console.log("inner promise");//1
    resolve(42);
});
promise.then(function(value){
    console.log(value);//3
});
console.log("outer promise");//2

//why not 213
//Which callback function in new Promise is synchronous?
//Callback function! = Asynchronous http://liubin.org/promises-book/#mixed-onready.js

Correspondence of several shortcut methods

Quick way

Corresponds to

Remarks

Promise.resolve

new Promise(function (resolve) {resolve() })

Promise.reject

new Promise(function (resolve, reject) {reject() })

.catch

.then(undefined, onRejected)

The reserved words under IE8 cannot be used as attribute names, only ["catch"]

1 .catchand .thenno essential difference, but to divide occasions

function throwError(value) {
   //Throw an exception
    throw new Error(value);
}

//onRejected will not be called
Promise.resolve(42).then(throwError, onRejected);
//Change to this will be called
Promise.resolve(42).then(throwError).then(null, onRejected);

The callback function specified by the onRejected parameter in the .then method actually targets the promise object or the previous promise object, rather than the first parameter specified in the .then method, that is, the object pointed to by onFulfilled, so capture Less than the error thrown by onFulfilled. This is the reason why then and catch behave differently.

2. .thenand .donedifferences

doneMethods are provided in other libraries that can be used instead then, but there is no doneprovision in the ES6 Promises and Promises/A+ specifications .

if (typeof Promise.prototype.done ==='undefined') {
    Promise.prototype.done = function (onFulfilled, onRejected) {
        this.then(onFulfilled, onRejected).catch(function (error) {
            setTimeout(function () {
                throw error;
            }, 0);
        });
    };
}

Seen from the implementation code:

  1. Encapsulates the catchexecution of the method, and setTimeout callback throw errorsolves the problem of Promise.resolve(42).then(throwError);forgetting to use catch for exception handling by throwing the error , and causing the error to be swallowed and not reporting the error
function JSONPromise(value) {
    return new Promise(function (resolve) {
        resolve(JSON.parse(value));
    });
}

//Because there is a try catch mechanism inside the promise, the error is caught by the internal catch, but it is not processed and will not be thrown
var string = "{}";
JSONPromise(string).then(function (object) {
    conole.log(object);//console spelling error
});
  1. doneIt does not return a promise object, so you cannot use catchother methods to form a method chain after done

Then chain operation of promise

function doubleUp(value) {
    return value * 2;
}
function increment(value) {
    return value + 1;
}
function output(value) {
    console.log(value);//=> (1 + 1) * 2
}

var promise = Promise.resolve(1);
promise
    .then(increment)
    .then(doubleUp)
    .then(output)
    .catch(function(error){
       //It will be called when an exception occurs in the promise chain
        console.error(error);
    });

The value of return in each method is not only limited to string or numeric types, but can also be complex types such as objects or promise objects. The value of return will be packaged accordingly by Promise.resolve (return value of return); so no matter what value is returned in the callback function, the final result of then is to return a newly created promise object.

A new Promise object is returned after each then call

From the first glance of the code, aPromise.then(...).catch(...) looks like a series of method chain calls to the original aPromise object. However, in fact, whether it is the then or catch method call, a new promise object is returned. In other words, it is Promise#thennot only as simple as registering a callback function, but also transforming the return value of the callback function, creating and returning a promise object.

var aPromise = Promise.resolve(100);
aPromise.then(function (value) {return value * 2});
aPromise.then(function (value) {return value * 2});
aPromise.then(function (value) {console.log(value);});//100

//Anti-pattern
function badAsyncCall() {
    var promise = Promise.resolve();
    promise.then(function() {
       //arbitrary processing
        return newVar;
    });
    return promise;
}

//2: Make a promise chain call to `then`
var bPromise = new Promise(function (resolve) {
    resolve(100);
});
bPromise.then(function (value) {
    return value * 2;
}).then(function (value) {
    return value * 2;
}).then(function (value) {
    console.log("2: "+ value);//=> 100 * 2 * 2
});

//mode
function anAsyncCall() {
    var promise = Promise.resolve();
    return promise.then(function() {
       //arbitrary processing
        return newVar;
    });
}

Promise.all() & Promise.race()

1. Promise.all

Receive an array of promise objects as a parameter, it will call when all the promise objects in this array become resolve or reject state.then method.

Promise.all([req.comment(), req.posts()]).then(function (results) {
    console.log(results);//[comment, posts]
});
  • The order of the obtained data array is the same as the order of the incoming all
  • Passed to Promise.allpromise not executed sequentially one by one, but started simultaneously executed in parallel

2. Promise.race

As long as a promise object enters the FulFilled or Rejected state, the subsequent processing will continue

//task1 (delay 10ms) task2 (delay 20ms)
//same execution time
Promise.race([req.task1(10), req.task2(20)]).then(function (value) {
    console.log(value);//10 output completed first
});

Although subsequent operations will be performed as long as a Promise is no longer in the pending state, it will not cancel the execution of other Promise objects passed in.

In the ES6 Promises specification, there is no concept of canceling (interrupting) the execution of a promise object. We must ensure that the promise eventually enters one of the resolve or reject states. In other words, Promise is not suitable for processing where the state may be fixed. There are also some libraries that provide cancellation of promises.

Deferred (jQuery) and Promise

The XHR is encapsulated with Promise above, and the following is rewritten with Deferred object based on Promise.

function Deferred() {
    this.promise = new Promise(function (resolve, reject) {
        this._resolve = resolve;
        this._reject = reject;
    }.bind(this)); 
}
Deferred.prototype.resolve = function (value) {
    this._resolve.call(this.promise, value);
};
Deferred.prototype.reject = function (error) {
    this._reject.call(this.promise, error);
};

function getURL(url) {
    var deferred = new Deferred();
    var xhr = new XMLHttpRequest();
    xhr.open("get", url, true);
    xhr.onload = function () {
        if (xhr.status === 200) {
            deferred.resolve(xhr.responseText);
        }
        else {
            deferred.reject(new Error(xhr.statusText));
        }
    };
    xhr.onerror = function () {
        deferred.reject(new Error(xhr.statusText));
    };
    xhr.send();
    return deferred.promise;
}

//run
getURL("xxx").then(function (value) {
    console.log(value);
}).catch(function (error) {console.error(error)});

Similarities and differences

  1. Deferred contains promises and has some privileged methods to change the state; there are no resolve methods on promises (passed into the constructor via parameters)
  2. In Promise, the main processing logic is generally written in the constructor, and the resolve and reject methods are called
  3. Deferred does not need to write the processing logic as a large block of code and enclose it with the Promise constructor. You only need to create the deferred object first, and you can call the resolve and reject methods at any time.

In other words, Promise represents an object. The state of this object is still uncertain, but its state will either become normal (FulFilled) or an abnormal value (Rejected) at a point in the future; and the Deferred object represents The fact that a processing has not ended, when its processing is over, the processing result can be obtained through Promise.

var gitalk = new Gitalk({ clientID: '82f3fb6574634b43d203', clientSecret: '5790d9fdbfe9340d29810b694b3b2070a9a3b492', repo:'zfengqi.github.io', owner:'zfengqi', admin: ['zfengqi'], id: winMode: true .loc.pathname, }); gitalk.render('gitalk-container');

Reference: https://cloud.tencent.com/developer/article/1563239 Promise Foundation-Cloud + Community-Tencent Cloud