In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-14 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
This article introduces the knowledge of "what are the three mistakes in using Promises in JavaScript". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!
Wrap everything in the Promise constructor
The first mistake is also one of the most obvious mistakes, but I find that developers make this mistake surprisingly frequently.
When you first learn Promises, you will learn about the constructor of Promise, which can be used to create a new Promises object.
Perhaps because people usually start learning by wrapping some browser API (such as setTimeout) in a Promise constructor, they have a deep-rooted belief that the only way to create a Promise object is to use a constructor.
Therefore, it is usually written as follows:
Const createdPromise = new Promise (resolve = > {somePreviousPromise.then (result = > {/ / A pair of result to do some operations resolve (result);});})
As you can see, some people used then to do some work on the resulting result of somePreviousPromise, but later decided to wrap it again in a constructor of Promise in order to store the result of that operation in a variable of createdPromise, presumably to do more with that Promise later.
This is obviously unnecessary. The whole point of the then method is that it returns a Promise itself, which means that the callback function in then is executed after somePreviousPromise is executed, and the parameters of then are the results returned by the successful execution of somePreviousPromise.
So, the previous code is roughly equivalent to:
Const createPromise = somePreviousPromise.then (result = > {/ / perform some operations on result return result})
If it is written in this way, it will be much simpler.
But why do I say it's just roughly equivalent? What's the difference?
If you are inexperienced and do not observe carefully, it may be difficult to find that there is actually a huge difference in error handling between the two, which is more important than the redundancy of the first paragraph of code.
Suppose somePreviousPromise fails for some reason and throws an error. For example, a HTTP request is sent in this Promise, and the API responds to a 500 error.
It turns out that in the previous piece of code, we wrapped one Promise into another Promise, and we couldn't catch the error at all. To resolve this problem, we must make the following changes:
Const createdPromise = new Promise ((resolve, reject) = > {somePreviousPromise.then (result = > {/ / A pair of result to do some operations resolve (result);}, reject);})
We simply add a reject parameter to the callback function and then use it by passing it to then as the second argument. It is important to remember that it is important that the then method accepts a second optional parameter for error handling.
Now if somePreviousPromise fails for some reason, the reject function will be called, and we will be able to handle errors on createdPromise as usual.
Does this solve all the problems? I'm sorry, it's not.
We have dealt with possible errors in somePreviousPromise itself, but we still have no control over what happens in the callback function that is the first argument to the then method. There may be some errors in the code that performs some operations on result in the comment area, and if the code in this area throws any errors, the second parameter of the then method, reject, still cannot catch these errors.
This is because the error handler, which is the second parameter of the then method, only responds to errors that occur before the current then on the Promise chain.
Therefore, the most appropriate (and final) solution should be as follows:
Const createdPromise = new Promise ((resolve, reject) = > {somePreviousPromise.then (result = > {/ / A pair of result to do some operations resolve (result);}) .catch (reject);})
Note that this time we used the catch method-- because it will be called after the first then, and it will catch all errors thrown on the Promise chain. Whether the callback in somePreviousPromise or then fails, Promise will handle these situations as expected.
As you can see from the above example, there are a lot of details to deal with when wrapping code in the constructor of Promise. This is why it is best to use the then method to create a new Promises, as shown in the second section of code. It not only looks elegant, but also helps us avoid those extreme situations.
Comparison between Serial call then and parallel call then
Because many programmers have a background in object-oriented programming, it is common for them to call a method to change an object rather than create a new one.
This is probably why I see someone confused about what happens when the then method is called on Promise.
Compare the following two pieces of code:
Const somePromise = createSomePromise (); somePromise. Then (doFirstThingWithResult). Then (doSecondThingWithResult); const somePromise = createSomePromise (); somePromise. Then (doFirstThingWithResult); somePromise. Then (doSecondThingWithResult)
Are they doing the same thing? It looks the same. After all, both pieces of code call then twice on somePromise, right?
No, this is another very common misunderstanding. In fact, these two pieces of code do completely different things. If you do not fully understand what is being done in two pieces of code, it can lead to very tricky errors.
As we said in the previous chapter, the then approach creates a completely new, independent Promise. This means that in the first piece of code, the second then method is not called on somePromise, but on a new Promise object, which means that doFirstThingWithResult is called as soon as the state of somePromise becomes successful. Then add a callback operation doSecondThingWithResult to the newly returned Promise instance
In fact, these two callbacks will be executed one by one-- ensuring that the second callback will not be called until the first callback is completed and there is no problem. In addition, the first callback will take the value returned by somePromise as an argument, but the second callback function will take the value returned by the doFirstThingWithResult function as an argument.
On the other hand, in the second piece of code, we call the then method on somePromise twice, basically ignoring the two new Promises objects returned from this method. Because then is called twice on the exact same Promise instance, we cannot determine which callback to execute first, and the order of execution here is uncertain.
In a sense, these two callbacks should be independent and independent of any previously invoked callbacks, which I sometimes regard as "parallel" execution. But, of course, in fact, the JS engine can only perform one function at a time-- you have no idea in what order they will be called.
The second difference between the two pieces of code is that in the second piece of code, both doFirstThingWithResult and doSecondThingWithResult receive the same parameter-- the result returned by somePromise successfully executed, and the return values of the two callback functions are completely ignored in this example.
Execute Promise immediately after creation
The reason for this misunderstanding is that most programmers have rich experience in object-oriented programming.
In the idea of object-oriented programming, it is often considered a good practice to ensure that the object's constructor itself does nothing. For example, an object that represents a database should not initiate a link to the database when calling its constructor using the new keyword.
Instead, you should provide a specific method, such as calling a method called init-- which will explicitly create the connection. In this way, an object does not perform any unexpected operations because it has been created. It will be executed in accordance with the specific requirements of the programmer.
But this is "not the way Promises works".
Consider the following example:
Const somePromise = new Promise (resolve = > {/ / create HTTP request resolve (result);})
You might think that the function that made the HTTP request was not called here because it is wrapped in the Promise constructor. In fact, many programmers want the then method to be called after it is executed on somePromise.
But this is not the case. After the Promise is created, the callback is executed immediately. This means that when you move on to the next line after creating the somePromise variable, your HTTP request may have been executed, or may already be in the execution queue.
We say Promise is "eager" because it performs the actions associated with it as quickly as possible. Instead, many people expect Promises to be "lazy", that is, to be called only when necessary (for example, when the then method is first called on Promise). This is a misunderstanding. Promise is always eager's, not lazy's.
But what if you want to delay the execution of Promise? What if you want to delay issuing the HTTP request? Is there some strange mechanism built into Promises that allows you to perform similar operations?
The answer sometimes exceeds the expectations of developers. Function is a lazy mechanism. They are executed only if the programmer explicitly calls them using the () syntax. Simply defining a function doesn't actually do anything. Therefore, the best way to make Promise "lazy" is to simply wrap it in a function!
The specific code is as follows:
Const createSomePromise = () = > new Promise (resolve = > {/ / create HTTP request resolve (result);})
Now, we wrap the invocation of the Promise constructor in a function. In fact, it hasn't really been called yet. We also changed the variable name from somePromise to createSomePromise because it is no longer a Promise object-- but a function that creates and returns a Promise object.
The Promise constructor (and the callback function with a HTTP request) is called only when the function is executed. So now we have a Promise for lazy, and we only execute it when we really want it to execute.
In addition, note that it comes with another feature. We can easily create another Promise object that can perform the same operation.
If, for some strange reason, we want to make two identical HTTP requests and execute them at the same time, we only need to call the createSomePromise function twice. Or, if the request fails for any reason, we can re-request it using the same function.
This shows that wrapping Promises in functions (or methods) is convenient, so it should be natural for JavaScript developers to develop with this pattern.
Ironically, if you have read my article Promises vs Observables, you will know that programmers who write Rx.js often make the opposite mistake. They encode Observable as if they were "eager" (consistent with Promises), when in fact they are "lazy". Therefore, wrapping an Observables in a function or method usually makes no sense and is actually harmful.
This is the end of the content of "what are the three mistakes in using Promises in JavaScript". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.