The promise of an asynchronous js solution

1. Promise definition

Promise is a solution to asynchronous programming that makes more sense and is more powerful than traditional solutions — callback functions and events.

reference

  • Promisra + Usage specifications

To understand:

  • Without asynchrony, promises are not needed.
  • Promises aren’t asynchronous per se, just a way for us to write asynchronous code

2. Promise specifications

When Es6 incorporated promises into its specification, it followed A corresponding standard – the Promise A+ specification.

It is summarized as specification 4321

4:4 Big terms 3:3 states 2:2 events 1:1 objects

2.1 Four Terms

  1. Fulfill (fulfill) : a set of operations such as state changes and callback execution that occur when a promise succeeds. Although fulfill is adopted as fulfill, resolve is adopted as fulfill in later generations.

  2. Reject: A sequence of actions that occurs when a promise fails.

  3. Eventual Value: The so-called final value refers to the value transferred to the solution callback when the promise is solved. Since the promise has the characteristics of one-off, when this value is passed, it marks the end of the promise waiting state, so it is called the final value, sometimes directly referred to as value.

  4. Reason: The rejection reason, the value passed to the rejection callback when a promise is rejected.

2.2 Three states

  • Pending state
  • This is a big pity.
  • (Rejected)

When a promise is in the wait state, it must meet the following conditions:

  • You can migrate to the execute or reject state

This is a big pity.

In the execution state, a promise must satisfy the following conditions:

  • You cannot migrate to any other state
  • You must have an immutable end value

(Rejected)

In the rejection state, a promise must satisfy the following conditions:

  • You cannot migrate to any other state
  • There must be an immutable cause

2.3 Two types of events

For the three states, there are only the following two conversion directions:

  • Pending – > fulfilled
  • Pendeing – > the rejected

When the state transitions, events are emitted.

If it is Pending — > Fulfiied, onFulFilled event will be triggered. If it is Pendeing — > Rejected, onFulFilled event will be triggered

2.4 One Object

This is a promise object

3. Basic use of promise

3.1 Basic Usage

let p = new Promise(function (resolve,reject) {
            reject("no");
        })
        console.log('p :', p);
Copy the code

The two arguments in the callback function are used to transition the state:

Resolve, select state from PENDING — > fullFilled Reject, select state from Pending — > Rejected

3.2 then method

When the state transitions, events are emitted.

Ondepressing event will be triggered if it is pending — > FulfiIED

If it is Pendeing — > Rejected, the onRejected event is triggered

For registration of events, the Promise object provides then methods, as follows:

3.3 Typical definition of Promise

3.3.1 Case 1: Reading files

const fs = require("fs");

let p = new Promise(function (resolve,reject) {
    fs.readFile("03 - based/js a.t xt." "."utf8",(err,date)=>{
        if(err){
            reject(err);
        }else{ resolve(date); }}); }); p.then(result= >{
      console.log('result :', result);
  }).catch(err= >{
      console.log('err :', err);
  });
Copy the code

3.3.2 Case 2: Return results based on random numbers

let p = new Promise((resolve,reject) = >{
    setTimeout((a)= >{
        let num = Math.random();
        if(num>0.5){
            resolve("success");
        }else{
            reject("fail"); }},1000);
});

p.then(result= >{
    console.log('result :', result);
},err=>{
    console.log('err :', err);
})
Copy the code

3.3.3 Reading File Encapsulation

const fs = require("fs");

function readFile(file){
    return new Promise((resolve,reject) = >{
        fs.readFile("file"."utf8",(err,date)=>{
            if(err){
                reject(err);
            }else{ resolve(date); }}); }); } readFile("a.txt").then(result= >{
    console.log('result :', result);
},err=>{
    console.log('err :', err);
})
Copy the code

3.4 All and race methods

-Leonard: All the races

Both All and Race are static methods of the Promise constructor object. Call directly with Promise as follows:

  • Promise. All ()
  • Promise. Reace ()
    • The return value is zeropromiseObject.

When you have multiple asynchronous operations, you often have two requirements :(somewhat similar to the logic and logic or in operators)

  1. Ensure that all asynchronous operations are complete before an operation, if only one failure, do not proceed

  2. Whenever there is an asynchronous operation article, an operation is performed in it.

Use all as follows

If there are any errors, see below

The use of the fax

4. Use a third-party Promise library

For third-party Promise libraries, there are two well-known libraries:

  • bluebird
  • q.js

Take Bluebird as an example to demonstrate its usage on the server side.

The first step is installation

Step two, use

4. Write the most complete version of the Promise Principle

I can enter the more hierarchical learning principle in Github. I have gradually encapsulated the basic version promise, the upgraded version promise and the complete version promise in Github.

Making address: github.com/quyuandong/…

The sample

The source code

// Define the state of the current promise
const PENDING = 'PENDING'
const RESOLVED = 'RESOLVED'
const REJECTED = 'REJECTED'
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
/ / promise object
class Promise {
    constructor(exector) {

        // Initialize status to wait state
        this.status = PENDING;
        // Success value
        this.value = undefined;
        // Cause of failure
        this.reason = undefined;

        // Store the successful callback function
        this.onResolvedCallbacks = [];
        // Store the failed callback function
        this.onRejectedCallbacks = [];

        // Successful handler function
        let resolve = (value) = > {
            if (this.status == PENDING) {
                this.value = value;     // Store successful values
                this.status = RESOLVED; // Change the current status to success
                this.onResolvedCallbacks.forEach(fn= > fn())
            }
        }

        // Failed handler
        let reject = (reason) = > {
            if (this.status == PENDING) {
                this.reason = reason;   // Cause of storage failure
                this.status = REJECTED; // Change the current state to failed state
                this.onRejectedCallbacks.forEach(fn= > fn())
            }
        }

        // When Pormise throws an exception
        try {
            exector(resolve, reject)    // Execute the function immediately
        } catch (e) {
            reject(e)
        }
    }

    /** * parameter: * @param {*} onFulfilled fulfilled ** @param {*} onFulfilled fulfilled This is a big promise, which may be fulfilled with onRejected. This is a big promise, which can be fulfilled all the time. Then, I need to return a promise * onFulfilled and onRejected. Its state is taken * if it is normal, this value is taken as the result of the success of the next THEN * */
    then(onFulfilled, onRejected) {

        P.teng ().then().then().then()...
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value= > value;
        onRejected = typeof onRejected === 'function' ? onRejected : err= > { throw err };

        /** * Create a promise and return a promise, so that the setTimeout function can be used to obtain the promise2 * try function: handle ondepressing which may throw an exception */
        let promise2 = new Promise((resolve, reject) = > {

            ------- synchronous operation (no asynchronous code in the executor)
            if (this.status == RESOLVED) {
                setTimeout((a)= > {
                    try {
                        let x = onFulfilled(this.value);// x can be a promise or a normal value
                        // If x is a promise(with its own state), we need to make pormise2 have the same state as x
                        resolvePromise(promise2, x, resolve, reject); // Handle the relationship between promise2 and x
                    } catch (e) {
                        reject(e)
                    }
                }, 0);
            }

            ------- synchronous operation (no asynchronous code in the executor)
            if (this.status === REJECTED) {
                setTimeout((a)= > {
                    try {
                        let x = onRejected(this.reason)
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e)
                    }
                }, 0)}// Wait state, save successful and failed operations ------- synchronous operation (asynchronous code in actuator)
            if (this.status === PENDING) {
                this.onResolvedCallbacks.push((a)= > {
                    setTimeout((a)= > {
                        try {
                            let x = onFulfilled(this.value)
                            resolvePromise(promise2, x, resolve, reject);
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)});this.onRejectedCallbacks.push((a)= > {
                    setTimeout((a)= > {
                        try {
                            let x = onRejected(this.reason)
                            resolvePromise(promise2, x, resolve, reject);
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)})}})returnpromise2; }}/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// Handle the relationship between promise2 and X, which is the return value of onFulfilled or onRejected
function resolvePromise(promise2, x, resolve, reject) {

    // if x === promise2, a circular reference is created and waits for completion
    if (promise2 === x) {
        return reject(new TypeError('my Chaining cycle detected for promise'))}// Prevent multiple calls
    let called;

    // x is an object (not null) or a function
    if(x ! = =null && (typeof x === "object" || typeof x === "function")) {

        try {
            // It is possible that x will be manually added with a then attribute
            let then = x.then;

            if (typeof then === 'function') {   // x is a promise

                // equivalent to x.teng (y=>{},r=>{})
                then.call(x, y => {
                    if (called) return;
                    called = true;

                    // Return a promise
                    resolvePromise(promise2, y, resolve, reject)
                }, r => {
                    if (called) return;
                    called = true;

                    // Use promise to pass down failed results
                    reject(r)
                })
            } else {    // if x is an object, it returns an object
                resolve(x)
            }
        } catch (e) {   // When x throws an exception
            if (called) return;
            reject(e)
        }
    } else {  //x is an ordinary value
        resolve(x)
    }
}

/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// resolve static method
Promise.resolve = function (val) {
    return new Promise((resolve, reject) = > {
        resolve(val)
    });
}


/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// reject static methods
Promise.resolve = function (val) {
    return new Promise((resolve, reject) = > {
        reject(val)
    });
}


/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// race static method
Promise.race = function (promises) {
    return new Promise((resolve, reject) = > {
        for (let i = 0; i < promises.length; i++) {
            promises[i].then(resolve, reject)
        }
    });
}


/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// all (get all promises, execute then, place the results in an array, and return them together)
Promise.all = function (promises) {
    let arr = [];
    let y = 0;
    function processData(index, data) {
        arr[i] = data;
        y++;
        if (y == promises.length) {
            return arr;
        };
    };

    return new Promise((resolve, reject) = > {
        for (let i = 0; i < promises.length; i++) {
            promises[i].then(data= > {
                processData(i, data)
            }, reject)
        }
    })
}

/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// 
/** * To verify that promises are true, add the following code: /** * To verify that promises are true: /** * To verify that promises are true, add the following code: /** * To verify that promises are true: /** * Promises -aplus-tests [js file name] */


// Currently it is through his tests that he will test an object
/ / syntactic sugar
Promise.defer = Promise.deferred = function () {
    let dfd = {}
    dfd.promise = new Promise((resolve,reject) = >{
      dfd.resolve = resolve;
      dfd.reject = reject;
    });
    return dfd;
  }


/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// Export a promise
module.exports = Promise;


/** * Note: When asynchracy occurs in a promise, the successful and failed callback functions for then must be saved first, and then executed when the state in the promise changes
Copy the code