Update rule S6544: cover additionnal cases from typescript-eslint's no-misused-promises
(#1733)
This commit is contained in:
parent
f8e8478f48
commit
88273ac629
@ -1,5 +1,5 @@
|
||||
{
|
||||
"title": "Promise executor functions should not be async",
|
||||
"title": "Promises should not be misused",
|
||||
"type": "BUG",
|
||||
"status": "ready",
|
||||
"remediation": {
|
||||
@ -7,8 +7,8 @@
|
||||
"constantCost": "5min"
|
||||
},
|
||||
"tags": [
|
||||
"async",
|
||||
"promise"
|
||||
"promises",
|
||||
"async"
|
||||
],
|
||||
"defaultSeverity": "Major",
|
||||
"ruleSpecification": "RSPEC-6544",
|
||||
|
@ -1,30 +1,77 @@
|
||||
In JavaScript, a promise is a mechanism to perform tasks in an asynchronous way. To this end, the language provides the `Promise` object which represents the eventual completion or failure of an asynchronous operation and its resulting value. A promise can be created with the `Promise` constructor accepting an executor function as an argument, which has `resolve` and `reject` parameters that are invoked when the promises completes or fails.
|
||||
Promises need to be resolved or awaited to return the expected value, otherwise, they return the promise object.
|
||||
|
||||
This rule forbids returning promises where another type is expected such as in:
|
||||
- conditionals
|
||||
- void returns
|
||||
- spread operators
|
||||
|
||||
// If you want to factorize the description uncomment the following line and create the file.
|
||||
//include::../description.adoc[]
|
||||
|
||||
== Why is this an issue?
|
||||
|
||||
Forgetting to await a promise is a frequent mistake. There are places where it makes no sense to use a promise, but the developer forgets to resolve it.
|
||||
|
||||
=== What is the potential impact?
|
||||
|
||||
Using a promise instead of its resolved value can have unexpected results leading to bugs.
|
||||
|
||||
- In conditionals, it will always return a truthy value.
|
||||
- In places where the expected type is void, returning a promise is often a mistake.
|
||||
- Using the spread operator on a promise will raise an exception.
|
||||
|
||||
The executor function of a promise can also be an async function. However, this usually denotes a mistake:
|
||||
|
||||
- If an async executor function throws an error, the error won't cause the created Promise to reject and will be lost therefore. This could make it difficult to debug and handle runtime errors.
|
||||
- If a Promise executor function is using `await`, this means that it's not necessary to use the Promise constructor, or the scope of the Promise constructor can be reduced.
|
||||
- If an async executor function throws an error, the error won't cause the created promise to reject and will be lost. Therefore, this could make it difficult to debug and handle runtime errors.
|
||||
- If a promise executor function is using `await`, this means that it's not necessary to use the `Promise` constructor, or the scope of the Promise constructor can be reduced.
|
||||
|
||||
== How to fix it
|
||||
|
||||
Fixing the issue requires removing the `async` keyword from the Promise executor function and adapting the body of the executor accordingly.
|
||||
If you mistook the promise with its resolved value, await the promise so it gets resolved correctly.
|
||||
Otherwise, you might need to adapt your code accordingly.
|
||||
|
||||
//== How to fix it in FRAMEWORK NAME
|
||||
|
||||
=== Code examples
|
||||
|
||||
==== Noncompliant code example
|
||||
|
||||
[source,javascript]
|
||||
[source,javascript,diff-id=1,diff-type=noncompliant]
|
||||
----
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
// ...
|
||||
resolve(false)
|
||||
});
|
||||
if (promise) {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
|
||||
==== Compliant solution
|
||||
|
||||
[source,javascript,diff-id=1,diff-type=compliant]
|
||||
----
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
// ...
|
||||
resolve(false)
|
||||
});
|
||||
if (await promise) {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
|
||||
==== Noncompliant code example
|
||||
|
||||
[source,javascript,diff-id=2,diff-type=noncompliant]
|
||||
----
|
||||
const p = new Promise(async (resolve, reject) => {
|
||||
doSomething('Hey, there!', function(err, res) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
doSomething('Hey, there!', function(error, result) {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
await saveResult(res)
|
||||
resolve(res);
|
||||
await saveResult(result)
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
|
||||
@ -33,26 +80,60 @@ await p;
|
||||
|
||||
==== Compliant solution
|
||||
|
||||
[source,javascript]
|
||||
[source,javascript,diff-id=2,diff-type=compliant]
|
||||
----
|
||||
const p = new Promise(async (resolve, reject) => {
|
||||
doSomething('Hey, there!', function(err, res) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
const p = new Promise((resolve, reject) => {
|
||||
doSomething('Hey, there!', function(error, result) {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
resolve(res);
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
|
||||
const res = await p;
|
||||
await saveResult(res);
|
||||
const result = await p;
|
||||
await saveResult(result);
|
||||
----
|
||||
|
||||
==== Noncompliant code example
|
||||
|
||||
[source,javascript,diff-id=3,diff-type=noncompliant]
|
||||
----
|
||||
apiCalls.forEach(async (apiCall) => {
|
||||
await apiCall.send();
|
||||
});
|
||||
----
|
||||
|
||||
==== Compliant solution
|
||||
|
||||
[source,javascript,diff-id=3,diff-type=compliant]
|
||||
----
|
||||
for (const apiCall of apiCalls) {
|
||||
await apiCall.send();
|
||||
}
|
||||
----
|
||||
|
||||
=== How does this work?
|
||||
|
||||
In JavaScript, a promise is a mechanism to perform tasks asynchronously.
|
||||
To this end, the language provides the `Promise` object which represents the eventual completion or
|
||||
failure of an asynchronous operation and its resulting value.
|
||||
A promise can be created with the `Promise` constructor accepting an executor function as an argument,
|
||||
which has `resolve` and `reject` parameters that are invoked when the promise completes or fails.
|
||||
|
||||
The logic of the promise is executed when it is called, however, its result is obtained only when the promise is resolved or awaited.
|
||||
|
||||
//=== Pitfalls
|
||||
//=== Going the extra mile
|
||||
|
||||
== Resources
|
||||
|
||||
=== Documentation
|
||||
|
||||
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise[MDN Promise]
|
||||
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises[MDN Using promises]
|
||||
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function[MDN Async function]
|
||||
|
||||
//=== Articles & blog posts
|
||||
//=== Conference presentations
|
||||
//=== Standards
|
||||
|
Loading…
x
Reference in New Issue
Block a user