Introduction of promise

Promise is an asynchronous programming solution added to the ES6 standard and is typically used to indicate the final completion (or failure) of an asynchronous operation. The Promise standard was proposed to solve the problem of JavaScript hell callback.

grammar

var p = new Promise( function(resolve, reject) {... }/* executor */  );
p.then((a)= > {})  / / the resolve to success
.catch((a)= > {});   / / reject failure
Copy the code

The constructor

The Promise constructor executor functions, resolve and reject, are passed as arguments to the executor (the executor function is called before the Promise constructor returns the constructed Promise instance object). When the resolve and reject functions are called, the state of the promise will be fulfilled or Rejected, respectively. Asynchronous operations are usually performed internally by the executor. Once the asynchronous operation is completed (which may succeed or fail), either the resolve function is called to change the promise state to fulfilled, or the Reject function is called to change the promise state to Rejected. If an error is thrown in the Executor function, the promise state is Rejected. The return value of the executor function is ignored.

describe

A Promise object does not necessarily have a value immediately after it is created, but is just a proxy result that can exist in three states:

  • Pending: An initial state (waiting state) that is neither successful nor failed.
  • This is a pity: which means that the operation will be completed successfully.
  • Rejected: Indicates that the operation fails and is completed.

methods

Promise.all(iterable)

This method returns a new Promise object. Typically, this method takes an iterable argument containing a list of promises that will be triggered when all of them succeed, and will immediately stop the execution of other promises if one fails. When all the results in iterable have been successfully executed, the new Promise object returns all the results as an array. When there is a failure, the new Promise object returns the failure message.

Promise.race(iterable)

When any child promise in the Iterable argument succeeds or fails, the parent promise immediately calls the parent promise’s binding handle using the child promise’s success return value or failure details as arguments and returns the promise object.

Promise.reject(rease)

Return a Promise object with a failed state and pass the given failure information to the corresponding handler

Promise.resolve(value)

Returns a Promise object whose state is determined by the given value. If the value is thenable(that is, the object with the THEN method), the final state of the returned Promise object is determined by the then method execution; Otherwise (the value is empty, a basic type, or an object with no THEN method), the Promise object will be returned with the state of FULFILLED and the value will be passed to the corresponding THEN method. In general, if you don’t know if a value is a Promise object, use promise.resolve (value) to return a Promise object so that the value can be used as a Promise object.

The instance

Now that the dry explanation is over, let’s use a concrete example to illustrate the various states and methods:

// create promise1 with 2 arguments resolve,reject
const p1 = new Promise((resolve, reject) = > {
 console.log('I would have done it from the start! ')
 setTimeout((a)= > {
  resolve('timeout 1')
 }, 1000) }) // promise2 const p2 = new Promise((resolve, reject) = > {  setTimeout((a)= > {  resolve('timeout 2')  }, 2000) }) console.log(p1, p2, 'P1, P2 state') // promise.race method, where any success or failure executes the then method Promise.race([p1, p2]).then(res= > {  console.log(res, 'the race results') }) / / Promise. All methods Promise.all([p1, p2]).then(res= > {  console.log(res, 'all the results')  console.log('At this time:', p1, p2, 'P1, P2 state') }) // promise. reject method test Promise.reject('failure').catch(err= > console.log('Promise.reject:' + err)) // promise. resolve method test Promise.resolve(1).then(r= > console.log('promise. resolve result 1:' + r)) Promise.resolve(p1).then(r= > console.log('promise. resolve result 2:' + r)) Copy the code

The above code and execution results are simply illustrativePromiseCreate, exist, and use of methods. More on this belowPromiseHow to use.

How to use promise

This article begins by suggesting that Promise solves the notorious hell callback problem on the front end. What is a hell callback? Here is a simple scenario and implementation method to explain:

scenario

The front end is usually the following scenario, we need to implement a user to modify the avatar function. First of all, we need to compress an image and submit it to the back end. The back end returns the SAVED URL of the image, and the front end submits the saved URL and user ID to the server to modify the user profile picture.

  1. Asynchrony 1: loading images
  2. Asynchrony 2: Compress images
  3. Asynchronous 3: Upload pictures
  4. Asynchronous 4: Commit and save

Approximate code implementation:

// Read avatar, asynchronous process, execute callback function after success
function readImg(callback) {
 const img = new Image();
 img.onload = function () {
  callback && callback(img)
 } }  // Compress an image asynchronously, and execute the callback function after success function compression(img, callback) {  zipImg(img, callback) } // Last user profile picture, asynchronous request function uploadImg(img, callback) {  $.ajax({  url: '/upload'. data: img,  success: function (url) {  callback && callback(url)  }  }) } // Save the final data, user profile picture, asynchronous request function saveData(url, callback) {  $.ajax({  url: '/save'. data: {id, url},  success: function (res) {  callback && callback(res)  }  }) } // Save the function function submit() {  readImg(function (img) {  compression(img, function (img) {  uploadImg(img, function (url) {  saveData(url, function (res) {  console.log(res)  })  })  })  }) } Copy the code

The above scenario is very common in our development process. Due to the asynchronous nature of JS, the result of asynchronous execution can only be obtained in the callback function, so there is the final callback hell. This process is extremely difficult to troubleshoot, and it is nested layer upon layer, and the code is extremely difficult to maintain and unattractive. To take advantage of the chaining of the promise, we can change the above code to the following form:

function submit() {
 readImg().then(img= > {
  return compression(img)
 }).then(img= > {
  return uploadImg(img)
 }).then(url= > {  return saveData(url)  }).then(res= > {  console.log(res)  }).catch(err= > {  console.log(err)  }) } Copy the code

You can see that the structure of the code is not only tiled, but exception handling is also simple: you only need to catch one exception at the end to catch the exception throughout the process.

usage

Promise to create

The way to create a variable:

const myFirstPromise = new Promise((resolve, reject) = > {
  / /? Do some asynchronous operations and end up calling one of the following:
  // resolve(someValue); // fulfilled
  / /? or
  // reject("failure reason"); // rejected
}); myFirstPromise.then(res= >{  DoSomething / / success } ).catch(err= > {  DoSomething / / failure }) Copy the code

The way to create a function:

const myFirstPromise = function() {
 return new Promise((resolve, reject) = > {
  // An asynchronous process
  // This is a big pity
  // reject() Reject
 }) } myFirstPromise().then(res= >{  DoSomething / / success } ).catch(err= > {  DoSomething / / failure }) Copy the code

Usage scenarios

In async, the result of async is given:

const myFirstPromise = function() {
 return new Promise((resolve, reject) = > {
  setTimeout((a)= > {
   resolve()
  },1000)
 }) } myFirstPromise.then((a)= >{  console.log('In a second! ') }) Copy the code

Use promise.all when multiple asynchrons require results to proceed:

Promise.all([func1(), func2(), func3()])
.then(([result1, result2, result3]) = > { /* use result1, result2 and result3 */ });
Copy the code

Resolve is implemented using the Promise. Resolve and reduce functions:

var funca = function (a) {
 return new Promise((resolve, reject) = > {
  setTimeout((a)= > {
   console.log(a, 'result funca');
   resolve(a + 1)
 }, 1000)  }) } var funcb = function (result) {  return new Promise((resolve, reject) = > {  setTimeout((a)= > {  console.log(result, 'result funcb')  resolve(2 + result)  }, 1000)  }) }  var funcc = function(result) {  return new Promise((resolve, reject) = > {  setTimeout((a)= > {  console.log(result, 'result funcc')  resolve(3 + result)  }, 1000)  }) } var funcd = function(d) {  console.log(d, 'result funcd')  return d + 4 } const applyAsync = (acc,val) = > acc.then(val); const composeAsync = (. dd) = > x= > dd.reduce(applyAsync, Promise.resolve(x)); const transformData = composeAsync(funca, funcb, funcc, funcd); transformData(1).then(result= > console.log(result,'last result')).catch(e= > console.log(e)); Copy the code

The above three asynchronous functions and one synchronous function, we usePromise.resolveThe feature executes three asynchronous functions sequentially, and finally inthenIt’s got the final execution result. Moreover, the above functions are reusable and can execute any number of asynchronous and synchronous functions sequentially.

Common mistakes

When writing the Promise chain, be aware of several errors shown in the following example:

// Error example, containing 3 problems!
doSomething().then(function(result) {
  doSomethingElse(result) // No return Promise and no necessary nesting Promise
  .then(newResult= > doThirdThing(newResult));
}).then((a)= > doFourthThing());
// Finally, there is no catch to terminate the Promise call chain, which may result in an uncaught exception Copy the code

The first mistake is not connecting things properly. This happens when we create a new Promise but forget to return it. Thus, the chain is broken, or rather, we have two independent chains competing (executing two asynchronously at the same time instead of one by one). This means that doFourthThing() will not wait for doSomethingElse() or doThirdThing() to complete, and will run in parallel with them, possibly unintentionally. Separate chains also have separate error handling, resulting in uncaught errors.

The second error is to nest unnecessarily, implementing the first error. Nesting also limits the scope of internal error handlers, which can lead to uncaught errors if unexpected. One variation is the Promise constructor anti-pattern, which combines redundant use and nesting of the Promise constructor.

The third mistake is forgetting to terminate the chain with a catch. This results in a rejection in the Promise chain that cannot be terminated in most browsers.

A good rule of thumb is to always return or terminate the Promise chain, and once you get a new Promise, return it. Here is the modified planarization code:

doSomething()
.then(function(result) {
  return doSomethingElse(result);
})
.then(newResult= > doThirdThing(newResult))
.then((a)= > doFourthThing()) .catch(error= > console.log(error)); Copy the code

compatibility

Most browsers already support itpromiseIn thebabelWith the blessing of… we need not worry.

conclusion

  1. PromiseisES6An asynchronous programming solution added to the standard, usually used to indicate the final completion (or failure) of an asynchronous operation.
  2. promiseThe characteristics of chain calls are resolvedjsThe callback hellThe problem.
  3. promiseProvides a range of properties and methods. Reasonable usePromise.allandPromise.resolveCan solve a lot of problems.

Write in the last

Next time, I will combine the explanation of this issue with some classic promise interview questions to have a deeper understanding of promise. Promise is too important, too useful. Async /await and promise will follow.

References:

Promise Usage Guide [1]

Related reading:

What is front-end asynchrony? In what cases does asynchrony occur?

Know the HTML5 Web Worker standard? Can JavaScript be multithreaded?

Learning is like rowing upstream, not to advance is to fall back, the rapid development of front-end technology, if you don’t keep learning every day, you will not keep up, I will accompany you, every day to push blog, progress with you, I hope you can pay attention to me, the first time to receive the latest article.

Daily interview questions:

The resources

[1]

Promise to use guide: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Using_promises