“This is the 12th day of my participation in the First Challenge 2022. For details: First Challenge 2022”

Basic knowledge of

In short, the Deferred object calls back to the function solution. In English, defer means “defer”, so the deferred object means “defer” to some future point. So it’s also called a deferred object.

Let’s start with an example of waiting for an asynchronous operation to complete to do something:

let p = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    console.log('complete')
    resolve(1)},1000)})// Wait for the timer to finish output OK
p.then((res) = > {
  console.log('ok', res)
})
Copy the code

We found that the Promise and the timer were coupled, meaning that the timer had to be written inside the Promise because the state of the Promise had to be changed by waiting for the timer to complete. Next, decoupling, we want the outside to control the state of the Promise.

let resolveFn // Save resolve for external calls
let p = new Promise((resolve, reject) = > {
  resolveFn = resolve
})

setTimeout(() = > {
  console.log('complete')
  resolveFn(1)},1000)

p.then((res) = > {
  console.log('ok', res)
})
Copy the code

We save resolve in a global variable for external calls, and reject in a new variable if necessary, which is omitted because it is not used here.

Three global variables may be required, and it is best to store them in an object to prevent variable collisions.

let deferred = {}
deferred.promise = new Promise((resolve, reject) = > {
  deferred.resolve = resolve
  deferred.reject = reject
})

setTimeout(() = > {
  console.log('complete')
  deferred.resolve(1)},1000)

deferred.promise.then((res) = > {
  console.log('ok', res)
})
Copy the code

As can be seen from the above code, the Deferred is mainly used internally to maintain the state of the asynchronous model; Promises are externally exposed through the then() method to add custom logic.

The APIS and abstract model of the Promise/Deferred pattern are concise. It encapsulates the immutable parts of the business in the Deferred and gives the mutable parts to the Promise.

The project of actual combat

Now that we have the Promise deferred object in hand, let’s look at how to use it.

1. Reduce code nesting

let fs = require('fs');

// Implement the Promise deferred object, defer
let Deferred = function () {
  let dfd = {};
  dfd.promise = new Promise((resolve, reject) = > {
    dfd.resolve = resolve;
    dfd.reject = reject;
  })
  return dfd
}

// function read () {
// return new Promise((resolve, reject) => {
// fs.readFile('./a.txt', 'utf8', (err, data) => {
// if (! err) resolve(data)
/ /})
/ /})
// }
// Reduce code nesting

function read () {
  let defer = Deferred()
  fs.readFile('./a.txt'.'utf8'.(err, data) = > {
    if(! err) defer.resolve(data) })return defer.promise
}

read().then((data) = > {
  console.log(data)
})
Copy the code

2. Multiple places want to control the state of a Promise, and the callback only needs to be executed once.

let deferred = {}
deferred.promise = new Promise((resolve, reject) = > {
  deferred.resolve = resolve
  deferred.reject = reject
})
// The order of asynchronous operations is uncertain
setTimeout(() = > {
  deferred.resolve()
}, 10 * Math.random())

setTimeout(() = > {
  deferred.resolve()
}, 10 * Math.random())

// Execute the callback as soon as 1 asynchronous operation completes
deferred.promise.then(() = > {
  console.log('ok')})Copy the code

3. Cooperation scheme between multiple asynchrony, multiple delay objects are used together.

let Deferred = function () {
  let dfd = {};
  dfd.promise = new Promise((resolve, reject) = > {
    dfd.resolve = resolve;
    dfd.reject = reject;
  })
  return dfd
}

let d1 = Deferred()
let d2 = Deferred()

Promise.all([d1.promise, d2.promise]).then((res) = > {
  console.log(res) // [ 'Fish', 'Pizza' ]
})

d1.resolve( "Fish" )
d2.resolve( "Pizza" )
Copy the code

Conclusion:

Deferred objects implement promises and expose the resolve and Reject methods outside the constructor, making the state of the Promise object more flexible. There is still only one state change, and subsequent changes are ignored.