preface

This article will take you through the following tasks to help you master Promise.

  1. JS implements an asynchronous Scheduler with concurrency limits, ensuring that up to two tasks can be run simultaneously
  2. Realize the Promise. All
  3. Realize the Promise. Any
  4. Realize the Promise. Race
  5. Promise.allSettled
  6. Multiple functions that return promises are executed sequentially
  7. The Promise timeout design is implemented using promise.race

JS implements an asynchronous Scheduler with concurrency limits, ensuring that up to two tasks can be run simultaneously

JS implements an asynchronous Scheduler with concurrency limits, ensuring that up to two tasks can be run simultaneously. Complete the title

// implement an asynchronous Scheduler with concurrency limits.
// Ensure that a maximum of two tasks are running simultaneously.
// Improve the Scheduler class.
// Make the following program output correctly

class Scheduler {
	constructor() {
		this.count = 2
		this.queue = []
		this.run = []
	}

	add(task) {
                 // ...}}const timeout = (time) = > new Promise(resolve= > {
	setTimeout(resolve, time)
})

const scheduler = new Scheduler()
const addTask = (time, order) = > {
	scheduler.add(() = > timeout(time)).then(() = > console.log(order))
}

addTask(1000.'1')
addTask(500.'2')
addTask(300.'3')
addTask(400.'4')
// output: 2 3 1 4

// At the beginning, tasks 1 and 2 are queued
// At 500ms, 2 completes, output 2, and task 3 enters the queue
// at 800ms, 3 is complete, 3 is output, 4 is queued
// At 1000ms, 1 is complete and 1 is output
// at 1200ms, 4 is complete, output 4
Copy the code

The answer

class Scheduler {
  constructor() {
    this.awatiArr = [];
    this.count = 0;
  }
  async add(promiseCreator) {
    if (this.count >= 2) {
      await new Promise((resolve) = > {
        this.awatiArr.push(resolve);
      });
    }
    this.count++;
    const res = await promiseCreator();
    this.count--;
    if (this.awatiArr.length) {
      // Resolve of the previous promise
      this.awatiArr.shift()();
    }
    returnres; }}const scheduler = new Scheduler();
const timeout = (time) = > {
  return new Promise(r= > setTimeout(r, time))
}
const addTask = (time, order) = > {
  scheduler.add(() = > timeout(time))
    .then(() = > console.log(order))
}
// test
// addTask(1000, 1)
// addTask(500, 2)
// addTask(300, 3)
// addTask(400, 4)
Copy the code

explain

  1. If the current concurrency is greater than or equal to 2, generate a suspended Promise, add resolve to an array, and the following code is paused
  2. If the current concurrency is less than 2, perform the asynchronous operation immediately and pop the first push resolve from the array to change the state of the Promise after the asynchronous operation completes
  3. Because the Promise is resolved, the code that was initially suspended can continue to execute
  4. The key point is that the code is suspended if the Promise is not resolved or reject, and the Promise’s resolve or reject can be executed outside the Promise constructor

Explain very good articles

Realize the Promise. All

All () // End condition: There is a Promise rejected or all Promise resolved.

  1. Receives an array of Promise instances or an object with an Iterator interface
  2. Resolve becomes a Promise object if the element is not a Promise object
  3. If everything succeeds and the state becomes resolved, the returned values will be passed as an array to the callback
  4. Once there is a failure, the state changes to Rejected, and the return value passed directly to the callback All () is also the new Promise object
  5. Note that ⚠️, whether promise. all, any, race, or allSettled, is a 🉑️ iterator with a [symbol. iterator] method deployed (such as array\ String \map\set\ object with length property).
function promiseAll(可迭代) {
  let array = Array.from(iterable);
  let resolveNum = 0;
  let promiseNum = array.length;
  let lists = new Array(promiseNum);
  return new Promise((resolve, reject) = > {
    for (let i = 0; i < promiseNum; i++) {
      Promise.resolve(array[i]).then(res= > {
        lists[i] = res;
        resolveNum++;
        if (resolveNum === promiseNum) {
          return resolve(lists)
        }
      }).catch(reason= > {
        returnreject(reason); }); }}); }// promiseAll([1, Promise.reject(12)]).then(res => {
// console.log(res)
// }).catch(reason => {
// console.log(reason)
// });
Copy the code

Realize the Promise. Any

Realize the Promise. Any ()

  1. End condition: There is one Promise Resolved or all Promise Rejected returns an instance of type AggregateError.
  2. If none of the promises in the iterable succeed (that is, promises were rejected), an instance of the failed promise and AggregateError type is returned, which is a subclass of Error and is used to group single errors together.

There’s a new error type you’ve learned, AggregateError. Check it out

function promiseAny(可迭代) {
  let array = Array.from(iterable);
  let promiseNum = array.length;
  let rejectNum = 0;
  return new Promise((resolve, reject) = > {
    for (let i = 0; i < promiseNum; i++) {
      Promise.resolve(array[i]).then(res= > {
        return resolve(res);
      }).catch(error= > {
        rejectNum++;
        if (rejectNum === promiseNum) {
          return reject(new AggregateError(""."All promises were rejected"))}}); }}); }// var p1 = new Promise(function (resolve, reject) {
// setTimeout(reject, 500, "one");
// });
// var p2 = new Promise(function (resolve, reject) {
// setTimeout(reject, 600, "two");
// });
// promiseAny([p1, p2]).then(res => {
// console.log(res)
// }).catch(error => {
// console.log(error)
// });
Copy the code

Realize the Promise. Race

Implement promise.race () termination conditions: Once a Promise in an iterator is resolved or rejected, the returned Promise is resolved or rejected.

function promiseRace(可迭代) {
  let array = Array.from(iterable);
  let promiseNum = array.length;
  return new Promise((resolve, reject) = > {
    for (let i = 0; i < promiseNum; i++) {
      Promise.resolve(array[i]).then(res= > {
        return resolve(res);
      }).catch(error= > {
        returnreject(error); }); }}); }// var p1 = new Promise(function (resolve, reject) {
// setTimeout(resolve, 500, "one");
// });
// var p2 = new Promise(function (resolve, reject) {
// setTimeout(reject, 600, "two");
// });
// promiseRace([p1, p2]).then(res => {
// console.log(res)
// }).catch(error => {
// console.log(error)
// });
Copy the code

Realize the Promise. AllSettled

  1. End condition: All the given promises have fulfilled or rejected promise.
  2. This is very depressing. For the promise is resolved, the object is {status: ‘fulfilled’, value: the promise value}
  3. {status: ‘rejected’, reason: the reason for the rejected}

At present, it is used in our SSR project, which will initiate multiple requests at the server at a time. It is impossible to discard successful requests after a request is hung up, but you can try this method.

function promiseAllSettled(可迭代) {
  let array = Array.from(iterable);
  let promiseNum = array.length;
  let num = 0;
  let list = new Array(promiseNum);
  return new Promise((resolve, reject) = > {
    for (let i = 0; i < promiseNum; i++) {
      let obj = {
        status: ' '
      };
      Promise.resolve(array[i]).then(res= > {
        obj.status = 'fulfilled';
        obj.value = res;
      }).catch(error= > {
        obj.status = 'rejected';
        obj.reason = error;
      }).finally(() = > {
        num++;
        list[i] = obj;
        if (promiseNum === num) {
          returnresolve(list); }}); }}); }// const promise1 = Promise.reject(3);
// const promise2 = new Promise((resolve, reject) => setTimeout(resolve, 100, 'foo'));
// promiseAllSettled([promise1, promise2]).then(res => {
// console.log(res)
// }).catch(error => {
// console.log(error)
// });
Copy the code

Multiple functions that return promises are executed sequentially

/ / implementation
function promiseSerial(array) {
  if (array.length === 0) throw 'At least one item in the parameter array'
  array.reduce((preP, nextP) = > {
    return preP.then(() = > nextP());
  }, Promise.resolve());
}

/ / implementation
async function promiseSerial1(array) {
  if (array.length === 0) throw 'At least one item in the parameter array'
  for (let promise of array) {
    awaitpromise(); }}const createPromise = (time, id) = > () = >
  new Promise(solve= >
    setTimeout(() = > {
      console.log(Date.now() / 1000);
      console.log("promise", id);
      solve();
    }, time)
  );
// test
// promiseSerial1([
// createPromise(1000, 1),
// createPromise(1000, 2),
// createPromise(1000, 3)
// ])
Copy the code

The Promise timeout design is implemented using promise.race

function resolveAfter(ms, value = undefined) {
  return new Promise((resolve, reject) = > {
    setTimeout(() = > {
      console.log('timeout');
      resolve(value || Promise.reject(new Error('Operation timed out')));
    }, ms);
  });
}
function PromiseTimeout(ms, promise) {
  return Promise.race([
    promise,
    resolveAfter(ms)
  ]);
}
// test
// var p1 = new Promise((resolve, reject) => {
// setTimeout(() => {
// console.log('p1');
// resolve('p1-resolved')
/ /}, 1000);
// })
// PromiseTimeout(100, p1).then(res => {
// console.log(res)
// }).catch(error => {
// console.log(error)
// });
Copy the code

The last

Writing in a hurry, this article is mainly personal understanding of the Promise, if there are mistakes also hope to correct.