What is Promose? (Necessary popular science)

The development community fumbled around with the callback trap of asynchronous functions, culminating in the Promise/A+. Its advantages are significant:

  1. With no new syntax added, it works instantly with almost any browser
  2. Organize code in queues that are easy to read and change
  3. A catch exception scheme is also generally available

This scheme was gradually improved in iteration and was finally incorporated into ES2015. In addition, ES2017 has added Await/Async, which can write asynchronous code in a sequential manner and even throw catch errors normally and maintain the same stack. The problem of asynchronous callbacks is completely solved.

Most browsers and Node.js now support Promises natively, and many libraries are starting to return Promise objects, with a variety of degraded adaptation strategies. Node.js 7+ is Await/Async.


The basic use of Promose

let Mypromise = require('./Promise') // This is a Promise function written by myselflet p1 = new Mypromise(function(resolve,reject){
    resolve('666')
})
p1.then(function(data){
    console.log(data)
},function(err){
    console.log(err)
})Copy the code

A Promise is a proxy object that has nothing to do with the original asynchronous operation. It takes an “executor” as an argument, and we put in the asynchronous (not necessarily asynchronous, as I’ll explain later, but you don’t have to go into that) operation that we were going to execute.

The executor starts executing immediately after the Promise instance is created. The executor comes with two arguments, resolve and Reject, which are functions that change the state of the Promise instance.

A Promise instance has three states:

  1. pending[To be determined] Initial state. The newly created instance is in this state
  2. fulfilledOperation successful, called in the executorresolve()The instance then switches to this state
  3. rejectedRejected operation failed, called in the executorreject()The instance then switches to this state

Once the state of the Promise instance changes, the function in the corresponding.then() argument is triggered to continue with the subsequent steps. In addition, the instance state of Promise will only change once, which will not change again after it is fulfilled or rejected.


Let’s look at how the Promise function aspect code is implemented:

functionPromise(executor) {// Executor is an execution functionletself = this; // Cache this to prevent errors self.status ='pending'; // Initialize state self.value = undefined; // Default success value self.reason = undefined; // The default failure causefunctionResolve (value) {// Success statusif (self.status === 'pending') {// Check the current status self.status ='resolved'; Resolved self.value = value; // Assign the default success status}}functionReject (reason) {// Failure statusif (self.status === 'pending') {// Determine the current state of the Promise if it is initialized self.status ='rejected'; // The pending state is rejected self.reason = reason; }} try {executor(resolve, Reject)} catch (e) {// A new Promise object throws a new Error('Wrong')
        reject(e);
    }
}

Promise.prototype.then = function(onFulfilled, onReject){    let self = this;   
    if(self.status === 'resolved'){ // 
        onFulfilled(self.value)
    }
    if(self.status === 'rejected'){
        onReject(self.reason)
    }
}
module.exports = Promise;Copy the code

The above is the basic implementation of Promise


Let’s try the result: when the Primose instance is in the resolve state, the result is shown below





Let’s test this: When the Primose instance is reject, it looks like this



As a result of the code, the ‘pedding’ state inside the Promise function can now be changed based on success and hundreds of states

What if both functions run at the same time!! The following



It only shows one result and the state changes to whoever executes first doesn’t execute both results

Now we have a rudimentary implementation of the synchronization method for the Promise function

Then continue to implement others such as (multiple THEN, asynchronous, Promise (then returns a new Promise object))


The successful methods in the THEN will be executed in order after the success. We can first talk about the successful callback in the THEN to the array, when the success is to call the successful array, the same is true when the failure

Define two arrays that received successfully and two arrays that failed as follows:

functionPromise(executor) {// Executor is an execution functionlet self = this;
    self.status = 'pending'; self.value = undefined; // Default success value self.reason = undefined; Self.onresolvedcallbacks = []; self.onresolvedCallbacks = []; / / storethenSuccessful callback self.onrejectedCallbacks = []; / / storethenFailed callbackfunctionResolve (value) {// Success statusif (self.status === 'pending') {
            self.status = 'resolved'; self.value = value; / / when successful, the inside of the array in sequence success function self. OnResolvedCallbacks. ForEach (function(fn) { fn(); }); }}functionReject (reason) {// Failure statusif (self.status === 'pending') {
            self.status = 'rejected'; self.reason = reason; / / when failure, failed to perform, in turn, the inside of the array function self. OnRejectedCallbacks. ForEach (function(fn) { fn(); })} try {executor(resolve, reject)} catch (e) {reject(e) {reject(e); }}Copy the code

And then in the then method we also need to say that the current state is pending and we need to do something about it

Promise.prototype.then = function(onFulfilled, onReject){
    let self = this;
    if(self.status === 'resolved'){ //
        onFulfilled(self.value)
    }
    if(self.status === 'rejected'){onReject(self.reason)} // When calledthenIt may not succeed or failif (self.status === 'pending') {/ / at this point no resolve no reject self. OnResolvedCallbacks. Push (function(){
            onFulfilled(self.value)
        })
        self.onRejectedCallbacks.push(function(){
            onReject(self.reason)
        })
    }
}Copy the code

Example code: The result is as follows



Use then twice: The number of times the then is called shows the number of successes


Chain call jquery, what jquery does is it returns this,promise does not return this,promise does it by returning a new promise, If either the successful callback or the failed callback in the THEN returns the result, the success in the next THEN will proceed, and if there is an error, the failure in the next THEN will proceed

Example code is as follows:

let p = new Promise(function(resolve,reject){
    resolve();
})
let p2 = p.then(function(){
    throw new Error('wrong');
})
p2.then(function(){// return a new Promise},function(err){ console.log(err); // output error})Copy the code

The code is as follows:

Promise.prototype.then = function(onFulfilled, onReject){
    let self = this;
    letpromise2; // Return promiseif (self.status === 'resolved') {
        promise2 = new Promise(function (resolve, reject) {
            try{
                onFulfilled(self.value);
            }catch (e){
                reject(e)
            }
        })
    }
    if (self.status === 'rejected') {
        promise2 = new Promise(function(resolve, reject) {try{onReject(self.reason)}catch (e){reject(e)}})} // when calledthenIt may not succeed or failif (self.status === 'pending') {
        promise2 = new Promise(function(resolve, reject) {/ / at this point no resolve no reject self. OnResolvedCallbacks. Push (function () {
                try{
                    onFulfilled(self.value)
                }catch (e){
                    reject(e)
                }
            });
            self.onRejectedCallbacks.push(function() { try{ onReject(self.reason) }catch (e){ reject(e) } }); })}return promise2;
}

Copy the code

If the first promise returns a normal value, the successful callback for the next THEN will be carried forward. If the first promise returns a promise, wait for the result of the returned promise to be passed to the next THEN


let p1 = new Promise(function(resolve,reject){
    resolve('333')
})
p1.then(function(data){
    return new Promise(function(resolve,reject){
        setTimeout(function () {
            resolve(100)
        },1000)
    })
},function(err){
    throw new Error('failure')
}).then(function (data) {
    console.log(data)
},function (err) {
    console.log(err)
})Copy the code


Promise.prototype.then = function(onFulfilled, onReject){
    let self = this;
    letpromise2; // Return promiseif (self.status === 'resolved') {
        promise2 = new Promise(function(resolve, reject) {// If there is an exception on success or failure, the returned promise should be in the failed state. // x can be a promise or a normal value.letx = onFulfilled(self.value); ResolvePromise (promise2, x, resolve, reject); }catch (e){ reject(e) } }) }if (self.status === 'rejected') {
        promise2 = new Promise(function (resolve, reject) {
            try{
                letx = onRjected(self.reason); resolvePromise(promise2, x, resolve, reject); }catch (e){reject(e)}})thenIt may not succeed or failif (self.status === 'pending') {
        promise2 = new Promise(function(resolve, reject) {/ / at this point no resolve no reject self. OnResolvedCallbacks. Push (function () {
                try{
                    let x = onFulfilled(self.value);
                    resolvePromise(promise2, x, resolve, reject);
                }catch (e){
                    reject(e)
                }
            });
            self.onRejectedCallbacks.push(function () {
                try{
                    letx = onRjected(self.reason); resolvePromise(promise2, x, resolve, reject); }catch (e){ reject(e) } }); })}return promise2;
}Copy the code

Next, implement the resolvePromise function

functionResolvePromise (promise2, x, resolve, reject) {// It is possible that the x returned here is someone else's promiseif(promise2 === x) {// There should be a type errorreturn reject(new TypeError('Circular reference'} // see if x is a promise. Promise should be an objectletcalled; // indicates whether the call succeeded or failedif(x ! == null && (typeof x ==='object' || typeof x === 'function') {// It could be a promise {}, see if there is one in this objectthenMethod, if anythenI thought he was a promise. Try {// {then: 1}let then = x.then;
            if (typeof then= = ='function') {// success then.call(x,function (y) {
                    if (called) return
                    called = trueResolvePromise (promise2, y, resolve, reject)}function(err) {// Failedif (called) return
                    called = truereject(err); })}else {
                resolve(x)
            }
        } catch (e) {
            if (called) return
            called = true; reject(e); }}else{// specify a common value 1 resolve(x); }}Copy the code

Quick implementation of other commonly used Promise methods:

// Method to catch errors promise.prototype. catch =function (callback) {
    returnThis. Then (null, callback)} // All methods Promisefunction(Promises) {// Promises is an array of promisesreturn new Promise(function (resolve, reject) {
        letarr = []; //arr is the result of the final return valueleti = 0; // Indicates the number of successesfunction processData(index, y) {
            arr[index] = y;
            if(++i === promises.length) { resolve(arr); }}for (let i = 0; i < promises.length; i++) {
            promises[i].then(function(y) {processData(I, y)}, reject)}})} // Just one promise succeeds. If the first one fails, it fails promise.race =function (promises) {
    return new Promise(function (resolve, reject) {
        for(var i = 0; i < promises.length; I ++) {promise [I]. Then (resolve,reject)}})function(value){
    return new Promise(function(resolve,reject){ resolve(value); })} // Generate a failed promise promise.reject =function(reason){
    return new Promise(function(resolve,reject){
        reject(reason);
    })
}
Promise.defer = Promise.deferred = function () {
    let dfd = {};
    dfd.promise = new Promise(function (resolve, reject) {
        dfd.resolve = resolve;
        dfd.reject = reject;
    });
    return dfd
}Copy the code

Write at the end: write an article for the first time, logic is a little disorderly, hope can help on everybody, everybody does not spray, have what mistake, please point out, very thank you! I’m sure I’ll rewrite it to make it better for you