Promise.deferred

  • Native does not have this method
// Promise.Deferred can reduce the Promise nesting native by one layer without this method

// Make a promise
function readFile(. args) {
  return new Promise((resolve, reject) = >{ fs.readFile(... args,(err,data) = > {
      if(err) returnreject(err); resolve(data); })})}Promise.deferred = function() {
  let dfd = {};
  dfd.promise = new Promise((resolve, reject) = > {
    dfd.resolve = resolve;
    dfd.reject = reject;
  })
  return dfd;
};

function readFile(. args) {
  let dfd = Promise.deferred(); // Create a promisefs.readFile(... args,function(err, data) {
    if(err) return dfd.reject(err);
    dfd.resolve(data);
  })
  return dfd.promise; // Return the Promise instance
}
Copy the code

catch

readFile("./xxx").then(data= > {
  console.log(data);
})
.catch(err= > {
  console.log(err);
})

// Catch catches an error, and the then method can be called
// Promise instance method
class Promise {
  catch(errFn) {
    return this.then(null, errFn)
  }
}
Copy the code

A static method

  • Promise.resolve
  • Promise.reject
Promise.resolve("hello").then(data= > {
  console.log(data); //'hello'
});
Promise.reject("hello").catch(err= > {
  console.log(err); // 'hello'
});

// The difference is that resolve has the effect of waiting
// Change the string passed to a Promise instance
Promise.resolve(new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve('hello')},1000)
})).then(data= > {
  console.log(data); // Wait for the promise to complete, print 'hello'
});
Promise.reject(new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve('hello')},1000)
})).catch(err= > {
  console.log(err); // Promise {
      
       } does not wait
      
});

/ / implementation
class Promise{
  constructor(executor) {
    const resolve = (value) = > {
      // The value passed in May be a promise
      // The logic added here is not part of the specification, but just the same as the native promise representation
      if(value instanceof Promise) {
        returnvalue.then(resolve, reject); }}}static resolve(value) {
    return new Promise((resolve, reject) = >{ resolve(value); })}static reject(err) {
    return new Promise((resolve, reject) = >{ reject(err); }}})Copy the code
  • Promise.all
  • Prototype method finally
const fs = require("fs").promises;
Promise.all([fs.readFile("name.txt"."utf8"), fs.readFile("age.txt"."utf8")])
  .then((data) = > {
    console.log(data);
  })
  .catch((err) = > {
    console.log(err);
  });

// Promise. All means success, failure, failure
// Promise.allSettled get all the results, regardless of success or failure
Promise.all = function (promises) {
  return new Promise((resolve, reject) = > {
    let result = [];
    let index = 0;
    function process(value, key) {
      result[key] = value;
      if (++index === promises.length) {
        // Use a timer to solve multiple asynchronous concurrency problemsresolve(result); }}for (let i = 0; i < promises.length; i++) {
      let p = promises[i];
      if (p && typeof p.then === "function") {
        p.then((data) = > {
          / / asynchronous
          process(data, i);
        }, reject); // If one promise fails, the final failure logic is executed
      } else {
        process(p, i); / / synchronize}}}); };Copy the code
/** * 1. Finally method that executes regardless of success or failure and can continue to be called then * data can be passed to the next then * 2. Finally callback that returns a promise will wait for the promise to complete. Pass the previous result to the following THEN * If the promise fails, the failed promise argument is passed to the failed callback of the next THEN */

Promise.resolve("ok")
.finally(() = > {
  // Finally functions have no arguments, passing the arguments above to the then below
  console.log("Call it whether it succeeds or fails.")
})
.then((data) = > {
  console.log('success', data);
})
.catch((err) = > {
  console.log('failure', err);
})

Promise.resolve("ok")
.finally(() = > {
  // Finally functions have no arguments, passing the arguments above to the then below
  console.log("Call it whether it succeeds or fails.")
  return new Promise((resolve, reject) = > {
    setTimeout(() = > {
      resolve("XXXXX");
    }, 1000)
  })
})
.then((data) = > {
  console.log('success', data);
})
.catch((err) = > {
  console.log('failure', err);
})

Promise.prototype.finally = function(cb) {
  return this.then((y) = > {
    // cb()
    // return y;
    // cb() may be a promise after execution, and has waiting effects whether or not it is packaged as a promise
    // Don't use promise.reject () because it doesn't wait
    // d is "XXXXX" and y is "OK"
    // If the cb executes an error, it skips the subsequent then execution logic and passes the error directly down
    return Promise.resolve(cb()).then(d= > y)
  },(r) = > {
    // cb();
    // throw r;
    return Promise.resolve(cb()).then(d= > { throw r })
  })
}

Copy the code
  • The asynchronous method is converted to the promise form
// 1. You can change all the original apis into the form of promises
const fs = require("fs").promises; 

// 2. Convert a single method to the form promise
const fs = require("fs");
const util = require("util"); // Another base module in Node (utility methods)
util.promisify(fs.readFile)

/ / use
let read = util.promisify(fs.readFile);
read("note.md"."utf8").then(data= > {
    console.log(data);
})
// How do I convert asynchronous apis that are not Promises into promises

function promisify(fn) {
    return function(. args) {
        return new Promise((resolve, reject) = >{ fn(... args,(err, data) = > {
                if(err) returnreject(err); resolve(data); }}})})function promisifyAll(obj) {
    for(let key in obj) {
        if(typeof obj[key] === 'function') { obj[key] = promisify(obj[key]); }}return obj;
}

Copy the code
  • Promise.race
/ / use
Promise.race([fs.readFile("a.md"."utf8"), fs.readFile("b.md"."utf8")]).then(data= > {
    console.log(data)
}, err= > {
    console.log(err);
});

/ / implementation
Promise.race = function(promises) {
    return new Promise((resolve, reject) = > {
        for(let i= 0; i < promises.length; i++) {
            let p = promises[i];
            if( p && typeof p.then === 'function'){
                p.then(resolve, reject);
            }else{/ / not a promiseresolve(p); }}})}Copy the code
  • An application of promise.race: Request timeout
// Simulate the promise to get the picture
let p = new Promise((resolve, reject) = > {
    setTimeout(() = > {
        resolve("Image loaded successfully")},3000);
});

function wrap(oldPromise) {
    let abort;
    // Add a promise (p2) that determines the success or failure of promise.race
    let p2 = new Promise((resolve, reject) = > {
        abort = reject;
    })
    let returnedPromise = Promise.race([oldPromise, p2]);
    returnedPromise.abort = abort;
    return returnedPromise
}

let newPromise = wrap(p);
setTimeout(() = > {
    newPromise.abort("Timeout");
}, 2000);
newPromise.then(data= > {
    console.log(data)
}, err= > {
    console.log(err);
})
Copy the code

How do I break the chain call of a promise

  • How do I keep Promise from walking down the then

    The solution is to return a waiting promise

  • There are two ways to interrupt
    1. Instead of using the original results, consider using promise.race
    2. Break the chain call and return a pending promise
Promise.resolve("1").then(data= > {
   console.log(data);
   return new Promise(() = >{}); // Return a promise that will take its state and will not proceed if it fails or succeeds
}).then(data= > {
   console.log(data);
})
Copy the code

Implement asynchronous concurrency upper limit control

class LimitPromise {
   constructor(max) {
       this._max = max; // The maximum concurrency of asynchronous tasks
       this._count = 0; // Number of tasks currently being executed
       this._taskQueue = []; // Queue of tasks waiting to be executed
   }
   /** * The call caller passes the asynchronous task function and its arguments * caller asynchronous task functions must be async functions or return promise functions * args Asynchronous task functions large argument list * RETURNS a new promise */
   call(caller, ... args) {
       return new Promise((resolve, reject) = > {
           // Create a task to determine whether the task is executed or enqueued
           const task = this._createTask(caller, args, resolve, reject);
           if(this._count >= this._max) {
               this._taskQueue.push(task);
           }else{ task(); }})}/** * _createTask Creates a task * caller actually executes the function * args executes the function's argument * returns a task function */
   _createTask(caller, args, resolve, reject) {
       return () = > {
           // Number of current requests +1
           this._count++;
           This is where the asynchronous task is actually called and the return (resolve, reject) of the asynchronous task is thrown up to the upper layercaller(... args) .then(resolve) .catch(reject) .finally(() = > {
               // Finally determines whether to execute the next task. This is where continuous consumption of the task queue is implemented
               // The consumption area of the task queue, using the promise. finally method to fetch the next task after the asynchronous task ends
               this._count --;
               if(this._taskQueue.length) {
                   let task = this._taskQueue.shift();
                   task()
               }
           })
       }
   }
}

/ / use
// Suppose we have a network request module called request.js, which contains the get and POST methods. In general, it is used like this:
const request = require('./request')
request.get('https://www.baidu.com')
 .then((res) = > {
   // Process the result
 })
 .catch(err= > {
   // Handle exceptions
 })
 
 
 
// Now we'll make it a restricted network request, assuming a maximum of 10 requests and calling it limitRequest.js. The implementation is as follows:
const LimitPromise = require('limit-promise')
const request = require('./request')
// Request the upper limit
const MAX = 10
// Core controller
const limitP = new LimitPromise(MAX)

// Wrap the request function with the core controller
function get (url, params) {
 return limitP.call(request.get, url, params)
}
function post (url, params) {
 return limitP.call(request.post, url, params)
}
/ / export
module.exports = {get, post}
Copy the code