“Code Tailor “provides technology related information and a series of basic articles for front-end developers. Follow the wechat public account” Rookie of Xiaohe Mountain “to get the latest articles.

preface

Before we start, we want to let you know that this article is a summary of the “Promise” chapter in ECMAScript6 by Yvonne nguyen. If you already know the following, you can skip this section and go straight to the title exercises

  • What is Promise?
  • How are promises created and used
  • Causes and advantages and disadvantages

If you are a little bit forgotten about some parts, 👇🏻 is ready for you!

Learning links

Promise to learn

Summary to summarize

concept

A Promise object represents a value that is not necessarily known when the Promise is created. It allows you to associate the eventual success return value or failure cause of an asynchronous operation with the appropriate handler. This allows asynchronous methods to return values as synchronous methods do: instead of returning the final value immediately, asynchronous methods return a Promise to give the value to the consumer at some point in the future.

Three states:

  • Pending: The initial state that has neither been granted nor rejected.
  • This is a big pity: this will be fulfilled successfully.
  • Rejected: Indicates that the operation fails.

Create and use

const promise1 = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve('foo')},300)
})

promise1
  .then((value) = > {
    console.log(value) // expected output: "foo"
  })
  .catch((error) = > {
    // called when an error occurs
    console.log(error)
  })
  .finally(() = > {
    // Execute whether it is right or wrong
    console.log('执行完毕')})console.log(promise1)
// expected output: [object Promise]
Copy the code
  • new Promise (executor)

Create a new Promise object. This constructor is primarily used to wrap functions that have not yet added promise support. The executor arguments are two: the resolve function, called when the operation completes successfully; Reject function, called when an error occurs

const promise1 = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve('foo')},300)
})

promise1.then((value) = > {
  console.log(value)
  // expected output: "foo"
})

console.log(promise1)
// expected output: [object Promise]
Copy the code

Commonly used method

  • Promise. All (iterable)

The promise.all () method takes an iterable of a Promise and returns only one Promise instance. The resolve callback is executed when all the incoming Promise’s resolve callbacks end, or when no promises are left in the iterable. Reject callback execution is a reject callback that throws an error as soon as any incoming Promise is executed or an invalid Promise is entered, and reject is the first error message thrown.

const promise1 = Promise.resolve(3)
const promise2 = 42
const promise3 = new Promise((resolve, reject) = > {
  setTimeout(resolve, 100.'foo')})Promise.all([promise1, promise2, promise3]).then((values) = > {
  console.log(values)
})
// expected output: Array [3, 42, "foo"]
Copy the code
  • Promise. AllSettled (iterable)

The promise.allSettled () method returns a Promise after all the given promises have fulfilled or rejected, with an array of objects, each representing the corresponding Promise result. This is often used when you have multiple asynchronous tasks that don’t depend on each other to complete successfully, or when you always want to know the outcome of each Promise.

const promise1 = Promise.resolve(3)
const promise2 = new Promise((resolve, reject) = > setTimeout(reject, 100.'foo'))
const promises = [promise1, promise2]

Promise.allSettled(promises).then((results) = >
  results.forEach((result) = > console.log(result.status)),
)

// expected output:
// "fulfilled"
// "rejected"
Copy the code
  • Promise. Race (iterable)

The promise.race (iterable) method returns a Promise that is resolved or rejected once a Promise in the iterator is resolved or rejected.

const promise1 = new Promise((resolve, reject) = > {
  setTimeout(resolve, 500.'one')})const promise2 = new Promise((resolve, reject) = > {
  setTimeout(resolve, 100.'two')})Promise.race([promise1, promise2]).then((value) = > {
  console.log(value)
  // Both resolve, but promise2 is faster
})
// expected output: "two"
Copy the code

Causes and advantages and disadvantages

Advantages:

  • Once the state changes, it never changes again, and you can get this result at any time
  • Asynchronous operations can be expressed as a flow of synchronous operations, avoiding layers of nested callback functions
  • The readability of callback hell has been somewhat resolved

Disadvantages:

  • Unable to cancel promise
  • When you are in a pending state, you cannot tell what stage you are currently in
  • Code redundancy and semantic ambiguity can also occur when there are a bunch of tasks

The “callback hell” created by asynchronous callback, with its chaotic logic, high coupling, and poor readability spawned Promises. For more on the asynchronous history of JavaScript, see here

The title self-test

What does the following code output?

const first = () = >
  new Promise((resolve, reject) = > {
    console.log(3)
    let p = new Promise((resolve, reject) = > {
      console.log(7)
      setTimeout(() = > {
        console.log(5)
        resolve(6)},0)
      resolve(1)
    })
    resolve(2)
    p.then((arg) = > {
      console.log(arg)
    })
  })

first().then((arg) = > {
  console.log(arg)
})
console.log(4)
Copy the code
Answer
// Result:

/ / = > 3
/ / = > 7
/ / = > 4
/ / = > 1
/ / = > 2
/ / = > 5
Copy the code

This question is mainly to understand the js implementation mechanism.

In the first Event loop, execute the macro task, the main script, new Promise immediately, print 3, execute the new Promise operation p, print 7, find setTimeout, put the callback into the next task queue (Event Quene), Then of P, let’s call it then1 and put it in the microtask queue, and then of first, let’s call it then2 and put it in the microtask queue. Run console.log(4) and output 4. The macro task is complete.

Then execute the microtask, then1, print 1, then2, print 3.

The first round of the event loop ends, and the second round begins. 5. Resolve (6) will not take effect because p’s Promise state will not change once it changes.


Two: the red light three seconds once, the green light one second once, yellow light two seconds once; How do I make three lights turn on again and again? (Implemented with Promise) Three lighting functions already exist:

function red() {
  console.log('red')}function green() {
  console.log('green')}function yellow() {
  console.log('yellow')}Copy the code
Answer
var light = function (timmer, cb) {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      cb()
      resolve()
    }, timmer)
  })
}

var step = function () {
  Promise.resolve()
    .then(function () {
      return light(3000, red)
    })
    .then(function () {
      return light(2000, green)
    })
    .then(function () {
      return light(1000, yellow)
    })
    .then(function () {
      step()
    })
}

step()
Copy the code

The red light will be on once every three seconds, the green light will be on once every second, and the yellow light will be on once every two seconds, which means that the red function will be executed once, the green function will be executed once every two seconds, and the yellow function will be executed once every one second. This can be done by recursion.

Of course, there are many other ways to achieve the effect shown, but only one way is provided here.


Three: implement mergePromise function, pass in the array in sequence, and put the returned data in the array data.

const timeout = (ms) = >
  new Promise((resolve, reject) = > {
    setTimeout(() = > {
      resolve()
    }, ms)
  })

const ajax1 = () = >
  timeout(2000).then(() = > {
    console.log('1')
    return 1
  })

const ajax2 = () = >
  timeout(1000).then(() = > {
    console.log('2')
    return 2
  })

const ajax3 = () = >
  timeout(2000).then(() = > {
    console.log('3')
    return 3
  })

const mergePromise = (ajaxArray) = > {
  // Implement your code here
}

mergePromise([ajax1, ajax2, ajax3]).then((data) = > {
  console.log('done')
  console.log(data) // Data is [1, 2, 3]
})

// Request separate output
/ / 1
/ / 2
/ / 3
// done
/ / [1, 2, 3]
Copy the code
Answer
// Save the result of executing the functions in the array
var data = []

The resolve method is called with no arguments and returns an Resolved Promise object.
var sequence = Promise.resolve()

ajaxArray.forEach(function (item) {
  // The first then method executes each function in the array,
  // The second then method takes the result of the array function's execution,
  // Add the result to data and return data.
  // The sequence reassignment extends the Promise chain
  sequence = sequence.then(item).then(function (res) {
    data.push(res)
    return data
  })
})

// When the loop is complete, return a Promise, i.e., sequence, whose [[PromiseValue]] value is data,
// Data (which holds the result of the execution of the function in the array) is passed as an argument to the next call to the then method.
return sequence
Copy the code

Ajax1, ajax2, and ajax3 are all functions, but they return a Promise when executed. We just execute them sequentially and put the result in data, but these functions are all asynchronous and want to execute them sequentially, and then print 1,2, 3 is not that simple. Let’s see.

function A() {
  setTimeout(function () {
    console.log('a')},3000)}function B() {
  setTimeout(function () {
    console.log('b')},1000)
}

A()
B()

// b
// a
Copy the code

In the example, we execute A sequentially, B but the output is B, A for these asynchronous functions, it does not execute one sequentially and then the next. So we’re going to use promises to control asynchronous flow, and we’re going to have to figure out how to execute one of these functions, and then execute the next.

ES 6 series Promise, we end here, thank you for your support! Your attention and praise will be the strongest motivation for us to move forward! Thank you!