Location>code7788 >text

Front-end fundamentals - interview must ask series (1): 2024, have not eaten through the Promise?

Popularity:56 ℃/2024-09-19 11:37:36

Write in the front:

Hello, everyone.lit. watching melons in the mountains (idiom); fig. a restricted view of the countrysideThe series of articles is to help you whether interview or development of the front-end of some basic but very important knowledge to recognize more in-depth and comprehensive.

The original reason for wanting to write this series of articles was that I realized that a lot of the basics of front-end are simple to use and the definitions look simple. A lot of people can talk about it when you ask them questions about it. But why use it? How is it better to use it? What is the principle? Let you realize how you do? These issues are many people have a half-understanding of certain points of knowledge I myself, only know to use, and even sometimes do not know why to use, not to mention the principle of adhering to the principle that the program and I either have a can run, as for how to run that rain I have no melon...

In this post we take a look at all aspects ofPromiseThe first thing you need to do is to sort out some of the points you know and don't know, so that you can speak thoroughly and shine in interviews, and so that you can use it in development to be more informed.

We will explain the following aspects of learning:

PromiseWhat is it?

define

  1. mdn description: aPromise is a proxy that represents a single agent that is used in the creation of thepromise values that are not necessarily known at the time. It allows you to associate a handler with the final success value or cause of failure of an asynchronous operation. This allows asynchronous methods to return values in the same way as synchronous methods: instead of returning the final value immediately, an asynchronous method returns a promise to provide that value at some point in the future.
  2. To summarize:Promiseis a technology proposed by the ES6 specification for asynchronous programming in JavaScript (reading and writing files, databases, requests, timers) solution, the original solution is to use callbacks nested in a way that is easy to cause back to hell (we'll talk about it later).
  3. Specifically:
    • Grammatically speaking:Promise is a constructor
    • Functionally:Promise object is used to encapsulate an asynchronous operation and get its success or failure value.
    • A promise can be used for both asynchronous and synchronous tasks.

Promisepresent state

The state is a property in the promise instance object: PromiseState, which has three values:

  1. Pending: the initial state, neither honored nor rejected, the state of being pending.
  2. resolved / fullfiled: means that the operation was completed successfully.
  3. Failed: means the asynchronous operation failed.

There are and only two cases of state change:

  1. pending change intoresolved / fullfiled
  2. pending change intorejected

State Change Description:

  • There are and will be only two cases of change, and the state of the promise object will change only once, from pending to either successful or failed.
  • Whether the state changes to success or failure, there will always be a result data (independent of whether there is a return or not).
  • The result of a successful execution is only generally referred to asvalueThe resultant value of an execution failure is generally referred to as thereason

Promiseresults

The result property of the Promise:

  • We can see in the instance objectPromiseResult This property, which holds the result of the success or failure of an asynchronous task execution.

How do I change the result of a promise?

  • resolve function: modify to a successful state (fullfiled).
  • reject function: modifies to a failed state (rejected).

Promiseworkflow

Why do you want to usePromise?

  1. gives us more flexibility in specifying callback functions when dealing with asynchronous operations.
    • In the old callback function approach, the callback function had to be specified before starting the asynchronous task;
    • promise: starts an asynchronous task --> returns a promise object --> binds a callback to the promise object;
    • Promise way, we can even specify it after the asynchronous task is finished and multiple callbacks can be specified.
  2. Support for chained calls can solve the callback hell problem.
    • Callback Inferno: Callback functions are called nested, and the result of the asynchronous execution of the external callback function is the condition of the nested callback execution.
    • Disadvantages of callback hell: not good for reading, not good for exception handling, complicated to maintain.

How to usePromise -- Detailed description of method parameters

Promise Constructor function: Promise(executor) {}

  • executor function: executor (resolve, reject) => {}
    • resolve function: the function we call when the internal definition succeeds value => {}
    • reject function: the function we call when the internal definition fails reason => {}
  • Explanation: executor will be called immediately synchronously inside the Promise, and asynchronous operations will be executed in the executor.That is, the executor function is not executed asynchronously

Promise Prototyping method

  1. methodologies:(onResolved, onRejected) => {}
    • onResolved function: success callback function (value) => {}
    • onRejected function: failed callback function (reason) => {}
    • then() always returns a new promise
    • The resulting state of the new promise is determined by the result of the execution of the callback function specified by then
      • throw an error
      • Returns the failed promise
      • Returns a successful promise
      • Returns any other value
  • Description: These two methods are used to specify the success callback for getting the success value and the failure callback for getting the failure reason.
  • The then method returns a new promise object
  1. Methods: (onRejected) => {}
    • onRejected function: failed callback function (reason) => {}

Methods in the Promise constructor itself

  1. Method: (value) => {}
    • value: success data or promise object
    • If you pass a non-promise object, the result is a successful promise object.
    • If the incoming parameter is a Promise object, the result of the parameter determines the result of the resolve.
  • Description: Returns a promise object that succeeds/fails.
let p1 = (520)
let p2 = (new Promise((resolve, reject) => {
  resolve('OK')
}))) // At this point, the p2 state is success, and the value of success is 'OK'Ï
  1. Method: (reason) =>{}
    • REASON: Reasons for failure
  • Description: Returns a failed promise object
let p = (520) // whatever is passed in returns a failed promise object
// Whatever is passed in will fail
  1. Methods: (promises) => {}
    • promises: an array of n promises.
    • Batch/send multiple asynchronous requests at once
    • When both succeed, the returned promise succeeds.
    • Once one fails, the returned promise fails.
  • Description: return a new promise, only succeed if all the promises succeed, if one fails, it fails directly
    • Successful results are an array of successful results for each promise object (in order).
    • The result of a failure is the result of the failure of the promise object that failed in this array
let p1 = new Promise((resolve, reject) => {
  resolve('OK')
})
let p2 = ('Success')
let p3 = ('Success')

const result = ([p1, p2, p3])
  1. Methods: (promises) => {}
    • promises: an array of n promises.
    • race: race/race
    • Description: Returns a new promise, the result state of the first completed promise is the final result state.
let p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('OK')
  }, 1000)
})
let p2 = ('Success')
let p3 = ('Success')

const result = ([p1, p2, p3]) // =>prove p2 results,on account ofp2 Change state first.

Promise The more common techniques used in development

In the actual development, we often encounter the need to send multiple requests to obtain data, when these requests do not depend on each other before, we use the normalPromise way to request or use theasync awaitThe way requests, are executed sequentially, a request is initiated after the previous request is completed, this is very inefficient, and the performance and experience is very poor, we rely on the part of the page requesting data will be blank for a long time, the user experience is very poor.

At this point we can use the() + async、awaitto concurrently request at the same time, so that requests can be initiated at the same time to achieve a parallel outgoing effect.

(promises) The result of the method is a result array containing all the asynchronous operations that correspond to the asynchronous operations in the promises array.

Here is a simple example:

// Methods for requesting interface data
const getApiData = async () {
const [res1, res2, res3] = await (
[
Api.getData1(),
Api.getData2(), Api.getData3()
Api.getData2(), Api.getData3(), [
]
)
}

A few notes:

  • Functions internally use theawait The function must use the async keyword;
  • Use only oneawait To() Use;
  • Do not add the await keyword to internal requests, otherwise they will still be requested sequentially and cannot be initiated in parallel;
  • on account of() The result is an array that corresponds to the internal asynchronous operation. We can directly deconstruct the array to get the result of each request, so that we can do subsequent operations on the requested values.

PromiseExample of style method encapsulation

  1. fs module encapsulation
function mineReadFile (path) {
  return new Promise((resolve, reject) => {
    // Read file
    require('fs').readFile(path, (err, data) => {
      // judgements
      if (err) reject(err)
      // successes
      resolve(data)
    })
  })
}

// call (programming)
mineReadFile("/file/").then(value => {
		(value)
	}, reason => {
		(reason)
	});
  1. Ajax Request Encapsulation
function sendAJAX(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest()
    // Setting the response data format
     = 'json'
    ('GET', url)
    ();
    // Disposal results
     = function () {
      if ( === 4) {
        // success story
        if ( >= 200 && < 300) {
          // Successful results
          resolve()
        } else {
          reject()
        }
      }
    }
  })
}

 // call (programming)
sendAJAX('/getJoke')
.then(value => {
  (value)
}, reason => {
  (reason)
})

write by handPromise

Before we start writing by hand, we need to figure out a few key things about promise:

  1. How do I change the state of a promise?

    • resolve(value): if it is currently pending, it will become resolved.
    • reject(reason): if it is currently pending, it becomes rejected
    • Throws an exception: if currently pending it becomes rejected
  2. A promise specifies (then method) multiple success/failure callback functions, are they all called?

    • is called whenever the promise changes to the corresponding state.
    let p = new Promise((resolve, reject) => {
      resolve('ok') // Here the state changes, so the next two callbacks are executed; if the state doesn't change, none of the following callbacks are executed.
    })
    
    // Specify the callback - 1
    (value => {
      (value)
    })
    
    // Specify callback - 2
    (value => {
      alert(value)
    })
    
    
  3. What is the order of changing the promise state and specifying the callback function, who executes first and who executes second?

    Brief description of the problem: At runtime, does resolve/reject change state first, or does the then method specify the callback to be executed first?

    • Both are possible, the normal case is to specify the callback before changing the state, but it is also possible to change the state first before specifying the callback

      • When the task in the executor function is a synchronized task (direct call to resolve()/reject()), change the promise state before specifying the callback function*.

      • When the task in the executor function is an asynchronous task, the then method executes first (specifying the callback) and then executes after the state is changed.

        // In this case, the hen method is executed first (with the specified callback), and is executed after the state is changed
        let p = new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve('OK')
          }, 1000)
        })
        
        (value => {
          (value)
        })
        
    • How do I change the state before specifying a callback?

      • Calling resolve()/reject() directly in the executor
      • Delay calling then() for a longer period of time
    • When will the data be available (when will the callback function execute)?

      • If the callback is specified first, then when the state changes (when resolve()/reject() is called), the callback function will be called to get the data
      • If the state is changed first, then when the function is specified (then method), the callback function will be called to get the data.
  4. What determines the result state of a new promise returned by ()?

    • Simple expression: determined by the result of the execution of the callback function specified by then()
    • Detailed expression:
      • If an exception is thrown, the new promise becomes rejected and reason is the exception thrown.
      • If any value other than the promise is returned, the new promise becomes resolved and value is the returned value.
      • If a new promise is returned, the result of this promise becomes the result of the new promise.
  5. promise How do I cascade multiple operational tasks?

    • promise's then() returns a new promise, which can be thought of as a chained call to then().
    • Chaining Multiple Synchronous/Asynchronous Tasks with then's Chain Calls
  6. Promise anomalous penetration?

    • When chaining then calls with promise, you can specify the failure callback at the end.
    • Any previous operations, except exceptions, are passed to the final failed callback to be handled
  7. Interrupting the promise chain

    • When chaining then calls with promise, you break in the middle and don't call the callback function after it.
    • Workaround: Return a promise object in the callback function in the pending state.
    let p = new Promise((resolve, reject) => {
    	setTimeout(() => {
            resolve('OK')
        }, 1000)
    })
    
    (value => {
        (111)
        return new Promise(() => {})
    }).then(value => {
        (222)
    })
    

Functional approach: wrapped into a constructor

function Promise(executor) {
// Add the property
= 'pending'
= null
// Declare the attribute Because onResolve and onReject can't be called directly on the instance object, the following then needs to be saved in the callback first.
= []
// Save the value of this for the instance object
const self = this // Common variable names are self _this that

// The resolve function
function resolve(data) {
// Determine the state
if ( ! == 'pending') return
// (this) => this points to the window, which is what you'll be modifying if you use this.
// 1. Modify the object's state (PromiseState)
= 'fulfilled'
// 2. Set the object's result value (PromiseResult) = data
= data
// Call the successful callback function
setTimeout(() => {
((item) => {
(data)
})
})
}

// The reject function
function reject(data) {
// Determine the state
if ( ! == 'pending') return
// 1. Modify the state of the object (PromiseState)
= 'rejected'
// 2. Set the object's result value (PromiseResult) = data
= data
// Call the failed callback function
setTimeout(() => {
((item) => {
(data)
})
})
}
try {
// Call [executor function] synchronously
executor(resolve, reject)
} catch (e) {
// Modify the state of the promise object
reject(e)
}
}

// Add the then method
 = function (onResolved, onRejected) {
const self = this
// Determine the callback function parameters
if (typeof onRejected ! == 'function') {
onRejected = (reason) => {
throw reason
}
}
if (typeof onResolved ! == 'function') {
onResolved = (value) => value
}
return new Promise((resolve, reject) => {
// Wrapping functions
function callback(type) {
function callback(type) {
// Get the result of the callback function
let result = type()
// Judgment
if (result instanceof Promise) {
(v) => {
(v) => {
resolve(v)
}, (r) => { resolve(v)
(r) => {
reject(r)
}
)
} else {
// The object state of the result is [success
resolve(result)
}
} catch (e) {
reject(e)
}
}
// Call the callback function based on the PromiseState.
if ( === 'fulfilled') {
setTimeout(() => {
callback(onResolved)
})
}
if ( === 'rejected') {
setTimeout(() => {
callback(onRejected)
})
}
// Determine the pending state
if ( === 'pending') {
// Save the callback function
({
onResolved: function () {
callback(onResolved)
}, onRejected: function () { callback(onResolved)
onRejected: function () {
callback(onRejected)
}, onRejected: function () { callback(onRejected)
})
}
})
}

// Add the catch method
 = function (onRejected) {
return (undefined, onRejected)
}

// Add the resolve method
 = function (value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
((v) => { if (value instanceof Promise) {
(v) => {
resolve(v)
}, {
(r) => {
reject(r)
}
)
} else {
// The status is set to success
resolve(value)
}
})
}

// Add the reject method
 = function (reason) {
return new Promise((resolve, reject) => {
reject(reason)
})
}

// Add the all method
 = function (promises) {
// Declare the variables
let count = 0 // count
let arr = [] // Array of results
// Iterate through
return new Promise((resolve, reject) => {
for (let i = 0; i < ; i++) {
promises[i].then(
(v) => {
// Know that the state of the object is success
// Add 1 for each success of the promise object.
count++; i++ { promises[i].then( (v) => { // Find out that the state of the object is successful // and add 1 to each successful promise object.
// Store the results of each current success for each promise object into an array.
arr[i] = v
// Judgment
if (count === ) {
// Modify the state
resolve(arr)
}
},
(r) => {
reject(r)
}
)
}
})
}

// Add the race method
 = function (promises) {
return new Promise((resolve, reject) => {
for (var i = 0; i < ; i++) {
promises[i].then(
(v) => {
// Change the status of the returned object to success
resolve(v)
},
(r) => {
// Change the status of the returned object to success
reject(r)
}
)
}
})
}

The class approach: encapsulation into a class

// Wrapped in a class
class Promise {
// Constructor
constructor(executor) {
// Add the attribute
= 'pending'
= null
// Declare the attribute Because onResolve and onReject can't be called directly on the instance object, the following then needs to be saved in the callback first.
= []
// Save the value of this for the instance object
const self = this // Common variable names are self _this that

// The resolve function
function resolve(data) {
// Determine the state
if ( ! == 'pending') return
// (this) => this points to the window, which is what you'll be modifying if you use this.
// 1. Modify the object's state (PromiseState)
= 'fulfilled'
// 2. Set the object's result value (PromiseResult) = data
= data
// Call the successful callback function
setTimeout(() => {
((item) => {
(data)
})
})
}

// The reject function
function reject(data) {
// Determine the state
if ( ! == 'pending') return
// 1. Modify the state of the object (PromiseState)
= 'rejected'
// 2. Set the object's result value (PromiseResult) = data
= data
// Call the failed callback function
setTimeout(() => {
((item) => {
(data)
})
})
}
try {
// Call [executor function] synchronously
executor(resolve, reject)
} catch (e) {
// Modify the state of the promise object
reject(e)
}
}

// then method encapsulation
then(onResolved, onRejected) {
const self = this
// Determine the callback function parameters
if (typeof onRejected ! == 'function') {
onRejected = (reason) => {
throw reason
}
}
if (typeof onResolved ! == 'function') {
onResolved = (value) => value
}
return new Promise((resolve, reject) => {
// Wrapping functions
function callback(type) {
function callback(type) {
// Get the result of the callback function
let result = type()
// Judgment
if (result instanceof Promise) {
(v) => {
(v) => {
resolve(v)
}, (r) => { resolve(v)
(r) => {
reject(r)
}
)
} else {
// The object state of the result is [success
resolve(result)
}
} catch (e) {
reject(e)
}
}
// Call the callback function based on the PromiseState.
if ( === 'fulfilled') {
setTimeout(() => {
callback(onResolved)
})
}
if ( === 'rejected') {
setTimeout(() => {
callback(onRejected)
})
}
// Determine the pending state
if ( === 'pending') {
// Save the callback function
({
onResolved: function () {
callback(onResolved)
}, onRejected: function () { callback(onResolved)
onRejected: function () {
callback(onRejected)
}, onRejected: function () { callback(onRejected)
})
}
})
}

// catch method
catch(onRejected) {
return (undefined, onRejected)
}

// The resolve method
static resolve(value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
((v) => { if (value instanceof Promise) {
(v) => {
resolve(v)
}, {
(r) => {
reject(r)
}
)
} else {
// The status is set to success
resolve(value)
}
})
}

// The reject method
static reject(reason) {
return new Promise((resolve, reject) => {
reject(reason)
})
}

// The all method
static all(promises) {
// Declare the variables
let count = 0 // count
let arr = [] // Array of results
// Iterate through
return new Promise((resolve, reject) => {
for (let i = 0; i < ; i++) {
promises[i].then(
(v) => {
// Know that the state of the object is success
// Add 1 for each success of the promise object.
count++; i++ { promises[i].then( (v) => { // Find out that the state of the object is successful // and add 1 to each successful promise object.
// Store the results of each current success for each promise object into an array.
arr[i] = v
// Judgment
if (count === ) {
// Modify the state
resolve(arr)
}
},
(r) => {
reject(r)
}
)
}
})
}

// The race method
static race(promises) {
return new Promise((resolve, reject) => {
for (var i = 0; i < ; i++) {
promises[i].then(
(v) => {
// Change the status of the returned object to success
resolve(v)
},
(r) => {
// Change the status of the returned object to success
reject(r)
}
)
}
})
}
}

asynccap (a poem)await

  • async/await is the ultimate weapon to eliminate asynchronous callbacks (write asynchronous code in a synchronous flow).
  • Purpose: Simplifies the use of promise objects, eliminating the need for then/catch to specify callback functions.
  • But it's not mutually exclusive with Promise
  • On the contrary, they complement each other.
  • Execute the async function and return the promise object.
  • wait is the then equivalent of promise.
  • try... .catch catches exceptions, which is the equivalent of catch for promises.

async function

  1. The return value of the function is the promise object
  2. The result of the promise object is determined by the return value of the async function execution

await expression

  1. The expression to the right of await is usually a promise object, but other values are possible
  2. If the expression is a promise object, await returns the value of the success of the promise.
  3. If the expression is any other value, the value is used directly as the return value of awaitÏ

Example of using async and await together:

// resource

const fs = require('fs')

// The way callback functions
('./resousrce/', (err, data1) => {
  if (err) throw err
  ('./resousrce/', (err, data2) => {
  	if (err) throw err
    ('./resousrce/', (err, data3) => {
  		if (err) throw err
      (data1 + data2 + data3)
		})
	})
})
// resource

const fs = require('fs')
const util = require('util')
const mineReadFile = ()

// async together with await combining
async function main() {
  try {
    // Read the contents of the first file
  	let data1 = await mineReadFile('./resourse/')
 	 	let data2 = await mineReadFile('./resourse/')
  	let data3 = await mineReadFile('./resourse/')
  
  	(data1 + data2 + data3)
  }catch(e) {
    (e)
  }
}
main()
// Async and await are combined to send an Ajax request.
function sendAJAX(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest()
    // Set the response data format
     = 'json'
    ('GET', url)
    ();
    // Process the result
     = function () {
      if ( === 4) {
        // Determine success
        if ( >= 200 && < 300) {
          // Successful result
          resolve()
        } else {
          reject()
        }
      }
    }
  })
}

// Segment interface address: /getJoke
let btn = ('#btn')

('click', async function () {
  // Get the segment information
  let duanzi = await sendAJAX('/getJoke')
  (duanzi)
})

Write it on the back.

Front-end stuff in fact, a lot of things are not difficult, just a lot of people rarely go deeper, to fully understand, we all just learn a general, will be used on the line;

This series of articles will be comprehensive and in-depth to take you to re-enforce the front-end foundation, some important and commonly used knowledge in-depth explanation;

Hopefully, after reading the article, you've gained something to use to make your interviews easier and more comfortable and brighter;

I believe that the people who can see here it, are wanting to make progress and want to grow small partners, hope that in the work of small partners of the promotion and salary increase, in the search for a job in the small partners of the interviews go well, harvest offer;

If it is helpful to you, give the author some attention, your support is the power of my creation!

Music Sharing

I don't know if there are partners who like rap, the author has an idea to share a rap that feels good at the end of each article, and of course you can share the songs that you think are good in the comment section.

Songs in this issue: "ghost face" - Pharaoh

  • Favorite line: a poor kid lives in a rich man's city and tries to fight the material with the spiritual.