Is this Promise you know

There are many words and codes in this article. It is recommended that you do not read the code first and study it carefully when you are interested.

Having been persecuted by old academics for more than ten years, we instinctively reject serious and educational articles. So I always don't want to take technical articles that seriously. Today is another topic written by countless people. (Skip 100,000 words here...) Still skip all the crap the author wants to say and go straight to the subject.

Slow ✋, Let's think about it first. What do you want to get out of this article?

1. Do you know what promise is?

According to Baidu translation, promise has the following main meanings:

Cough...Drive the wrong car unconsciously and call for~a timely brake.

promise in JavaScript is a tool for handling asynchronous problems. Yes, it is a tool. The scoop and spatula used to cook with you are the same definition.

It can handle tedious asynchronous problems in a more readable way, which improves code readability and reduces maintenance costs.

Chestnuts wave:

Traditional calls:

function change1(data) {
  // Processing data...
  change2(data)
  function change2(data) {
    // Processing data...
    change3(data)
    function change3(data) {
      // Processing data...
        change4(data)
        function change4(data) {
        // Processing data...
            change5(data)
            function change5(data) {
          // Processing data...
                change6(data)
                function change6(data) {
                    ..................
                    }
                }
            }
        }
    }
}

Promise call:

Promise.resolve(data)
.then(data => data) // Processing data
.then(data => data) // Processing data
.then(data => data) // Processing data
.then(data => data) // Processing data
.then(data => data) // Processing data
.then(data => data) // Processing data
.then(data => data) // Processing data
..................

Without saying anything else, this neat line of code looks pleasant.

Next, we can go a step further.

2. Synchronization and Asynchronization

As we mentioned earlier, promise is a tool for handling asynchronous problems. What is asynchronous? What is the problem that is not asynchronous? Kid, do you have many question marks????

Tasks are divided into asynchronous and synchronous tasks, not to mention official definitions, as explained in a paragraph.

2.1 What is synchronization

Synchronization: Enumerate a scenario, suppose you are in the bank now. If the person in front of you can't complete the business, you can't do it for you. At the same time, a salesperson can only handle one business, and when the previous business has reached the completion state (that is, finished processing), he can accept the next business.

2.2 What is asynchronous

Asynchronous: Similarly, enumerate a scene that changes to a restaurant where you are served by a waiter who will deliver the menu to the chef after ordering and then continue to serve the next customer. It is not necessary to wait until the current customer's service is over. There is no need to wait for the end of a complex, time-consuming cooking operation.

What a simple truth, Mausette feels so stuck...

Load 13, let's not talk more, just be serious~

3. Why promise appears

To explain this problem, first understand what callback hell is. Callback hell occurs because of asynchronous and callback functions. For chestnut eating pizza, there are several steps you must go through to eat pizza:

Want to eat pizza --> have a pizza shop --> have a cook in the store --> have ingredients for chef --> get ingredients for sale in the vegetable market --> harvest raw materials for making ingredients

I couldn't possibly eat pizza if I had problems with any of these steps. (I refuse to raise the bar here. I'm afraid)

As code:

function yuancailiao() {
  // Harvesting raw materials
  function chushou() {
    // Sell ingredients
    function shicai() {
      // Ingredients to the pizza shop
      function chushi() {
        // Ingredients in the hands of the cook
        function dameile() {
          // Pizza shops make pizza
          function chi () {
            // After all the hard work, I finally ate pizza.
          }
        }
      }
    }
  }
}

When nested levels are too deep, you will feel dizzy when looking for code, making your dizzy code a callback hell.

Promise.resolve('pizzeria')
.then(data => data) // Purchase raw materials 
.then(data => data) // Making Pizza
.then(data => data) // sit at the table
.then(data => data) // Start big quick eat
..................

Wow~The air is getting fresher. (As if I had written the same code twice ~~I hope I won't be beaten)

This is why promise appears.

4. Three states of promise

promise has three states during its run.

  • Pending initial state indicates pending
  • fulfilled operation succeeded
  • rejected operation failed

The state can only be pending to fulfilled or rejected. Irreversible.

Illustration:

5. Implement a simple promise

Finally, it's time to start coding. Are you ready? come on baby...

Before writing code, let's look at what promise has to do

  • Can be instantiated with new
  • Receive a function as a parameter
  • There are resolve and reject methods in the function
  • Three States
  • Available. The N and. catch operation
  • Errors that can be thrown or executed can be passed. catch for capture
  • call chaining

There seems to be nothing else. Write first.

Step 1: Define the constructor and modify the state

// Define a Promise constructor first
function Promise (executor) {
  // Define a state with an initial value of pending
  this.status = 'pending'

  // Success method
  this.success = () => {}

  // Failure Method
  this.error = () => {}

  // Define the resolve function
  function resolve(data) {
    if (this.status === 'pending') {
      this.status = 'fulfilled'
      // Execute the successful method after success, and pass the acquired data in the past
      this.success(data)
    }
  }
  // Define reject function
  function reject (errorMsg) {
    if (this.status === 'pending') {
      this.status = 'rejected'
      this.error(errorMsg)
    }
  }

  // Pass resolve and reject into the parameter function and --->bind this!!!
  executor(resolve.bind(this), reject.bind(this))
}

Step 2: Define then, catch methods

// Define the then method, receiving two functions as parameters success = () => {}, error = () => {}
Promise.prototype.then = function (success, error) {
  this.success = success
  this.error = error
}

// Define the catch method
Promise.prototype.catch = function (error) {
  this.error = error
}

Okay, a brand new Promise is done. Have a try with confidence.

new Promise1((res, rej) => {
  res(1)
}).then((data) => {
  console.log(data)
})
// Nothing is output.

What.! It doesn't match my expectations at all. Clever how could I have been stuck by a small bug. After a period of intense debugging, I finally found out what was wrong. When the resolve method executes, this.success has not yet been assigned. Change to the following so that you can output normally.

new Promise1((res, rej) => {
  setTimeout(() => {
    res(1)
  }, 0)
}).then((data) => {
  console.log(data)
})

Between the above questions, we have written another version. Look at the code:

// Define a Promise1 constructor first
  function Promise1 (executor) {
    // Define a state with an initial value of pending
    this.status = 'pending'

    // Success method
    this.successList = []
    //
    // Failure Method
    this.errorList = []

    // Add value Cache - - Add New - -
    this.value = null

    // Define the resolve function
    function resolve(data) {
      if (this.status === 'pending') {
        this.status = 'fulfilled'
        // Execute the successful method after success, and pass the acquired data in the past
        // - New additions--
        this.value = data
        this.successList.forEach(cb => cb(data))
      }
    }
    // Define reject function
    function reject (errorMsg) {
      if (this.status === 'pending') {
        this.status = 'rejected'
        // - New additions--
        this.value = errorMsg
        this.errorList.forEach(cb => cb(errorMsg))
      }
    }

    // Pass resolve and reject into the parameter function and --->bind this!!!
    executor(resolve.bind(this), reject.bind(this))
  }
  // Define the then method, receiving two functions as parameters success = () => {}, error = () => {}
  Promise1.prototype.then = function (success, error) {
    // If the state has changed at execution time, fetch the cached value directly
    if (this.status === 'fulfilled') {
      success(this.value)
    }
    if (this.status === 'rejected') {
      error(this.value)
    }
    // Otherwise, save the current function
    if (this.status === 'pending') {
      this.successList.push(success)
      this.errorList.push(error)
    }
  }

  // Define the catch method
  Promise1.prototype.catch = function (error) {
    if (this.status === 'pending') {
      this.error = error
      return
    }
    error(this.value)
  }

  new Promise1((res, rej) => {
    setTimeout(() => {
      res(1)
    }, 0)
  }).then((data) => {
    console.log(data)
  })

It's really my problem to forgive my guilt and let everyone see so much code at once. Try to correct it later.

Step 3: Error Capture

The parameters promise accepts can display throw errors, so we need to capture the errors. Very simple, just catch the executor error

try {
  // Pass resolve and reject into the parameter function and --->bind this!!!
  executor(resolve.bind(this), reject.bind(this))
} catch (e) {
  reject(e)
}

Step 4: Chain Call

The core of the chain call implementation is the need to return a new promise in the then method. Here's one thing to note. Reolve's data is wrapped using the resolve function, reject's data is wrapped using the reject function.

Promise1.prototype.then = function (success, error) {
  // If the state has changed at execution time, fetch the cached value directly
  if (this.status === 'fulfilled') {
    return new Promise1((resolve, reject) => {
      try{
        resolve(success(this.value))
      }catch(e) {
        reject(e)
      }
    })
  }
  if (this.status === 'rejected') {
    return new Promise1((resolve, reject) => {
      try{
        resolve(error(this.value))
      }catch(e) {
        reject(e)
      }
    })
  }
  // Otherwise, save the current function
  if (this.status === 'pending') {
    return new Promise1((resolve, reject) => {
      this.successList.push(() => {
        try {
          resolve(success(this.value))
        } catch (e) {
          reject(e)
        }
      })
      this.errorList.push(() => {
        try {
          resolve(error(this.value))
        } catch (e) {
          reject(e)
        }
      })
    })
  }
}

Test it:

new Promise1((res, rej) => {
  setTimeout(() => {
    res(1)
  }, 0)
}).then((data) => {
  console.log(data)
}).then(() => {
  console.log(2)
}).then(() => {
  console.log(3)
})

ok, you're done.

6. Implement promise.all and promise.race method

6.1 promise. Implementation of all method

Promise. Characteristics of all method

  • Receives an array with elements as promise objects
  • When all execution is complete, the results are returned
  • As long as there is one error, the error information is returned directly.

Chestnut Realization:

Promise.newAll = arr => {
  let result = [];
  return new Promise(function (resolve, reject) {
    let count = 0;
    arr.forEach(item => {
      item.then((res) => { // The list of promise s in arr, so execute the then method directly.
        result.push(res)
        count ++
                // If all succeeds, the resolve returns the result
        if (count === arr.length) {
          resolve(result)
        }
      }).catch((e) => {
        // Execute reject whenever there is an error
        reject(e)
      })
    })
  })
};

6.2 promise.race method

Promise. Characteristics of race method

  • Receives an array with elements as promise objects
  • Return the fastest possible content
  • reject after everything fails

Chestnut Realization:

Promise.newRace = arr => {
  return new Promise(function (resolve, reject) {
    let count = 0;
    arr.forEach(item => {
      item.then((res) => { // The list of promise s in arr, so execute the then method directly.
        // Return the fastest possible content
        resolve(res)
      }).catch((e) => {
        count ++
                // If all fails, the result returned by resolve
        if (count === arr.length) {
          reject(e)
        }
      })
    })
  })
};

7. A brief introduction to async await

Unconsciously, it became an old school or too young.

Now let's introduce these two guys.

async and await are syntax sugars for asynchronous programming provided by JavaScript that sweeten your way.

Look at the chestnuts first

function see(){
  return new Promise((resolve)=>{
    setTimeout(()=>{
      resolve(1)
    },3000)
  })
}
async function test(){
  let result = await see()
  console.log(result)
}
test()

async marks a function as an asynchronous function, waits for the result to return through await, and they change the execution order of the event loop (article is expected). And. They can also use try {} catch() {} to catch errors.

Another article was written with great effort. After reading the article. What do you understand?

Tags: Javascript Front-end Promise

Posted by etingwall on Mon, 02 May 2022 00:59:49 +0300