diff --git a/docs/rules/always-return.md b/docs/rules/always-return.md index 40527ec5..d3ccc1fc 100644 --- a/docs/rules/always-return.md +++ b/docs/rules/always-return.md @@ -1,22 +1,19 @@ # Return inside each `then()` to create readable and reusable Promise chains (always-return) Ensure that inside a `then()` you make sure to `return` a new promise or value. -See http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html (rule #5) -for more info on why that's a good idea. -We also allow someone to `throw` inside a `then()` which is essentially the same -as `return Promise.reject()`. +## Rule Details -#### Valid +Using a promise inside a `then()` without returning it (or using `await`) means +that a potential error from that promise will not be caught in subsequent +`catch()` callbacks. Additionally, returning a non-promise wraps it into a +Promise, allowing it to be used in promise chains, which is convenient when +mixing synchronous and asynchronous code. -```js -myPromise.then((val) => val * 2)); -myPromise.then(function(val) { return val * 2; }); -myPromise.then(doSomething); // could be either -myPromise.then((b) => { if (b) { return "yes" } else { return "no" } }); -``` +We also allow someone to `throw` inside a `then()` which is essentially the same +as `return Promise.reject()` in this scenario. -#### Invalid +Examples of **incorrect** code for this rule: ```js myPromise.then(function(val) {}) @@ -31,3 +28,29 @@ myPromise.then(b => { } }) ``` + +Examples of **correct** code for this rule: + +```js +myPromise.then((val) => val * 2); +myPromise.then(function(val) { return val * 2; }); +myPromise.then(doSomething); // could be either +myPromise.then((b) => { if (b) { return 'yes' } else { return 'no' } }); +``` + +## When Not To Use It + +If you want to allow non-returning `then()` callbacks, for example for +synchronous side-effects like below, you can safely disable this rule. + +```js +myPromise.then(val => { + console.log('promise complete') + console.log(val) +}) +``` + +## Further Reading + +- [We have a problem with promises](http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html) + (Rookie mistake #5: using side effects instead of returning) diff --git a/docs/rules/avoid-new.md b/docs/rules/avoid-new.md index 387623e9..1fb6b91e 100644 --- a/docs/rules/avoid-new.md +++ b/docs/rules/avoid-new.md @@ -1,3 +1,45 @@ # Avoid creating `new` promises outside of utility libs (use [pify][] instead) (avoid-new) +Avoid using `new Promise` in favour of utility libraries or +`Promise.resolve`/`reject`. + +## Rule Details + +Creating promises using `new Promise` can be used to promisify Node-style +callbacks. However, you can use libraries such as [pify][] or Node's +[`util.promisify`](https://nodejs.org/api/util.html#util_util_promisify_original) +instead. + +`new Promise` is also sometimes misused to wrap a value or +error into a promise. However, this can be done more concisely and clearly with +`Promise.resolve` and `Promise.reject`. + +Examples of **incorrect** code for this rule: + +```js +function promisifiedFn(arg) { + return new Promise((resolve, reject) => { + callbackStyleFn(arg, (error, result) => error ? reject(error) : resolve(result)) + }) +} + +new Promise((resolve, reject) => resolve(1)) +new Promise((resolve, reject) => reject(new Error('oops'))) +``` + +Examples of **correct** code for this rule: + +```js +const pify = require('pify') +const promisifiedFn = pify(callbackStyleFn) + +Promise.resolve(1) +Promise.reject(new Error('oops')) +``` + +## When Not To Use It + +If you are creating a utility library like pify or do not want to be notified +when using `new Promise`, you can safely disable this rule. + [pify]: https://www.npmjs.com/package/pify diff --git a/docs/rules/catch-or-return.md b/docs/rules/catch-or-return.md index d4812347..e15a30d9 100644 --- a/docs/rules/catch-or-return.md +++ b/docs/rules/catch-or-return.md @@ -3,69 +3,119 @@ Ensure that each time a `then()` is applied to a promise, a `catch()` is applied as well. Exceptions are made if you are returning that promise. -#### Valid +## Rule Details + +If a promise is not handled correctly, any error from that promise can cause +unhandled promise rejections. A promise can be handled using `catch()` or +returning it from a function, which will mean that it's the caller's +responsibility to handle the promise. + +Examples of **incorrect** code for this rule: ```js -myPromise.then(doSomething).catch(errors) +myPromise.then(doSomething) +myPromise.then(doSomething, handleErrors) // catch() may be a little better +``` + +Examples of **correct** code for this rule: + +```js +myPromise.then(doSomething).catch(handleErrors) myPromise .then(doSomething) .then(doSomethingElse) - .catch(errors) + .catch(handleErrors) function doSomethingElse() { return myPromise.then(doSomething) } ``` -#### Invalid +## Options + +### `allowThen` + +The second argument to `then()` can also be used to handle a promise rejection, +but it won't catch any errors from the first argument callback. Because of this, +this rule reports usage of `then()` with two arguments without `catch()` by +default. + +However, you can use `{ allowThen: true }` to allow using `then()` with two +arguments instead of `catch()` to handle promise rejections. + +Examples of **incorrect** code for the default `{ allowThen: false }` option: ```js -myPromise.then(doSomething) -myPromise.then(doSomething, catchErrors) // catch() may be a little better -function doSomethingElse() { - return myPromise.then(doSomething) -} +myPromise.then(doSomething, handleErrors) +``` + +Examples of **correct** code for the `{ allowThen: true }` option: + +```js +myPromise.then(doSomething, handleErrors) +myPromise.then(doSomething).catch(handleErrors) +``` + +### `allowFinally` + +This option allows `.finally()` to be used after `catch()` at the end of the +promise chain. This is different from adding `'finally'` as a +`terminationMethod` because it will still require the Promise chain to be +"caught" beforehand. + +Examples of **incorrect** code for the default `{ allowFinally: false }` option: + +```js +myPromise + .then(doSomething) + .catch(handleErrors) + .finally(cleanUp) ``` -#### Options +Examples of **correct** code for the `{ allowFinally: true }` option: -##### `allowThen` +```js +myPromise + .then(doSomething) + .catch(handleErrors) + .finally(cleanUp) +``` -You can pass an `{ allowThen: true }` as an option to this rule to allow for -`.then(null, fn)` to be used instead of `catch()` at the end of the promise -chain. +### `terminationMethod` -##### `allowFinally` +This option allows for specifying different method names to allow instead of +`catch()` at the end of the promise chain. This is +useful for many non-standard Promise implementations. You can use a single +string or an array of strings. -You can pass an `{ allowFinally: true }` as an option to this rule to allow for -`.finally(fn)` to be used after `catch()` at the end of the promise chain. This -is different from adding `'finally'` as a `terminationMethod` because it will -still require the Promise chain to be "caught" beforehand. +Examples of **incorrect** code for the `{ terminationMethod: 'done' }` option: -##### `terminationMethod` +```js +myPromise.then(doSomething).catch(handleErrors) +``` -You can pass a `{ terminationMethod: 'done' }` as an option to this rule to -require `done()` instead of `catch()` at the end of the promise chain. This is -useful for many non-standard Promise implementations. +Examples of **correct** code for the `{ terminationMethod: 'done' }` option: -You can also pass an array of methods such as -`{ terminationMethod: ['catch', 'asCallback', 'finally'] }`. +```js +myPromise.then(doSomething).done(handleErrors) +``` -This will allow any of +Examples of **correct** code for the +`{ terminationMethod: ['catch', 'asCallback', 'finally'] }` option: ```js -Promise.resolve(1) - .then(() => { - throw new Error('oops') - }) - .catch(logerror) -Promise.resolve(1) - .then(() => { - throw new Error('oops') - }) - .asCallback(cb) -Promise.resolve(1) - .then(() => { - throw new Error('oops') - }) - .finally(cleanUp) +myPromise.then(doSomething).catch(handleErrors) +myPromise.then(doSomething).asCallback(handleErrors) +myPromise.then(doSomething).finally(handleErrors) ``` + +## When Not To Use It + +If you do not want to be notified about not handling promises by `catch`ing or +`return`ing, such as if you have a custom `unhandledRejection` +(`unhandledrejection` in the browser) handler, you can safely disable this rule. + +## Further Reading + +- [We have a problem with promises](http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html) + (Advanced mistake #2: `then(resolveHandler).catch(rejectHandler)` isn't + exactly the same as `then(resolveHandler, rejectHandler)`) diff --git a/docs/rules/no-native.md b/docs/rules/no-native.md index 104dc297..95c52a85 100644 --- a/docs/rules/no-native.md +++ b/docs/rules/no-native.md @@ -4,15 +4,26 @@ Ensure that `Promise` is included fresh in each file instead of relying on the existence of a native promise implementation. Helpful if you want to use `bluebird` or if you don't intend to use an ES6 Promise shim. -#### Valid +## Rule Details + +If you are targeting an ES5 environment where native promises aren't supported, +ensuring that `Promise` is included from a promise library prevents bugs from +`Promise` being undefined. + +Examples of **incorrect** code for this rule: ```js -var Promise = require('bluebird') -var x = Promise.resolve('good') +var x = Promise.resolve('bad') ``` -#### Invalid +Examples of **correct** code for this rule: ```js -var x = Promise.resolve('bad') +var Promise = require('bluebird') +var x = Promise.resolve('good') ``` + +## When Not To Use It + +If you are targeting an environment that supports native promises, or using a +Promise shim, you should disable this rule. diff --git a/docs/rules/no-nesting.md b/docs/rules/no-nesting.md index 3225699f..fc12e2a5 100644 --- a/docs/rules/no-nesting.md +++ b/docs/rules/no-nesting.md @@ -1,15 +1,15 @@ # Avoid nested `then()` or `catch()` statements (no-nesting) -#### Valid +Nesting `then()` or `catch()` statements making code harder to understand and +maintain. Instead, you should return a promise from `then()` or `catch()` to +chain the promises. -```js -myPromise - .then(doSomething) - .then(doSomethingElse) - .catch(errors) -``` +## Rule Details + +Nesting `then()` or `catch()` statements is frequently redundant and does not +utilise promise chaining. This can result in code similar to "callback hell". -#### Invalid +Examples of **incorrect** code for this rule: ```js myPromise.then(val => @@ -28,3 +28,24 @@ myPromise.catch(err => doSomething(err).catch(errors) ) ``` + +Examples of **correct** code for this rule: + +```js +myPromise + .then(doSomething) + .then(doSomethingElse) + .catch(errors) +``` + +## When Not To Use It + +If you want to nest promises, for example to have different `catch()` handlers +to handle the different promises, you can safely disable this rule. + +## Further Reading + +- [Promises chaining on Javascript.info](https://javascript.info/promise-chaining) +- [Using Promises on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#Common_mistakes) +- [We have a problem with promises](https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html) + (Rookie mistake #1: the promisey pyramid of doom) diff --git a/docs/rules/no-new-statics.md b/docs/rules/no-new-statics.md index ab998031..bbfc87cc 100644 --- a/docs/rules/no-new-statics.md +++ b/docs/rules/no-new-statics.md @@ -11,7 +11,7 @@ problems reported by this rule. This rule is aimed at flagging instances where a Promise static method is called with `new`. -Examples for **incorrect** code for this rule: +Examples of **incorrect** code for this rule: ```js new Promise.resolve(value) @@ -20,7 +20,7 @@ new Promise.race([p1, p2]) new Promise.all([p1, p2]) ``` -Examples for **correct** code for this rule: +Examples of **correct** code for this rule: ```js Promise.resolve(value) @@ -31,5 +31,6 @@ Promise.all([p1, p2]) ## When Not To Use It -If you do not want to be notified when calling `new` on a Promise static method, -you can safely disable this rule. +If you do not want to be notified when calling `new` on a Promise static method +(for example when using a type checker like Flow or Typescript), you can safely +disable this rule. diff --git a/docs/rules/no-promise-in-callback.md b/docs/rules/no-promise-in-callback.md index a5d56b5a..0ef316ae 100644 --- a/docs/rules/no-promise-in-callback.md +++ b/docs/rules/no-promise-in-callback.md @@ -1 +1,31 @@ # Avoid using promises inside of callbacks (no-promise-in-callback) + +Discourages the use of promises inside callbacks. + +## Rule Details + +Promises and callbacks are different ways to handle asynchronous code and should +not be mixed. + +Examples of **incorrect** code for this rule: + +```js +doSomething((err, val) => { + if (err) console.error(err) + else doSomethingElse(val).then(console.log) +}) +``` + +Examples of **correct** code for this rule: + +```js +require('pify')(doSomething)() + .then(doSomethingElse) + .then(console.log) + .catch(console.error) +``` + +## When Not To Use It + +If you do not want to be notified when using promises inside of callbacks, you +can safely disable this rule. diff --git a/docs/rules/no-return-in-finally.md b/docs/rules/no-return-in-finally.md index 8188f529..2114fec8 100644 --- a/docs/rules/no-return-in-finally.md +++ b/docs/rules/no-return-in-finally.md @@ -3,18 +3,33 @@ Disallow return statements inside a callback passed to `finally()`, since nothing would consume what's returned. -#### Valid +## Rule Details + +Returning statements inside a `finally()` callback does not have any effect and +can indicate a misunderstanding of how `finally()` works. + +This rule does not report returning with concise arrow function expressions, +because it can be used to avoid unnecessary braces. + +Examples of **incorrect** code for this rule: ```js myPromise.finally(function(val) { - console.log('value:', val) + return val }) ``` -#### Invalid +Examples of **correct** code for this rule: ```js myPromise.finally(function(val) { - return val + console.log('value:', val) }) + +myPromise.finally(val => console.log('value:', val)) ``` + +## When Not To Use It + +If you do not want to be notified when using `return` in `finally()` callbacks, +you can safely disable this rule. diff --git a/docs/rules/no-return-wrap.md b/docs/rules/no-return-wrap.md index cfb76b2f..c4bfb9e2 100644 --- a/docs/rules/no-return-wrap.md +++ b/docs/rules/no-return-wrap.md @@ -1,34 +1,57 @@ # Avoid wrapping values in `Promise.resolve` or `Promise.reject` when not needed (no-return-wrap) Ensure that inside a `then()` or a `catch()` we always `return` or `throw` a raw -value instead of wrapping in `Promise.resolve` or `Promise.reject` +value instead of wrapping in `Promise.resolve` or `Promise.reject`. -#### Valid +## Rule Details + +Returning a value wrapped in `Promise.resolve` or `Promise.reject` inside a +`then()` or `catch()` callback is unnecessary. Returning a non-promise in one of +these callbacks automatically wraps it into a promise, and `throw`ing an error +is the same as using `Promise.reject`. + +Examples of **incorrect** code for this rule: ```js myPromise.then(function(val) { - return val * 2 + return Promise.resolve(val * 2) }) + myPromise.then(function(val) { - throw 'bad thing' + return Promise.reject('bad thing') }) ``` -#### Invalid +Examples of **correct** code for this rule: ```js myPromise.then(function(val) { - return Promise.resolve(val * 2) + return val * 2 }) + myPromise.then(function(val) { - return Promise.reject('bad thing') + throw 'bad thing' }) ``` -#### Options +## Options + +### `allowReject` + +Using `{ allowReject: true }` permits wrapping returned values with +`Promise.reject`, such as when you would use it as another way to reject the +promise. + +Examples of **correct** code for the `{ allowReject: true }` option: + +```js +myPromise.then(function(val) { + return Promise.reject('bad thing') +}) +``` -##### `allowReject` +## When Not To Use It -Pass `{ allowReject: true }` as an option to this rule to permit wrapping -returned values with `Promise.reject`, such as when you would use it as another -way to reject the promise. +If you don't want to be notified when returning values wrapped in +`Promise.resolve` or `Promise.reject` in `then()` or `catch()` callbacks, you +can safely disable this rule. diff --git a/docs/rules/param-names.md b/docs/rules/param-names.md index 5c6f70bd..80db4ffa 100644 --- a/docs/rules/param-names.md +++ b/docs/rules/param-names.md @@ -1,24 +1,31 @@ # Enforce consistent param names when creating new promises (param-names) -Enforce standard parameter names for Promise constructors +Enforce standard parameter names for Promise constructors. -#### Valid +## Rule Details + +Ensures that `new Promise()` is instantiated with the parameter names +`resolve, reject` to avoid confusion with order such as `reject, resolve`. The +Promise constructor uses the +[RevealingConstructor pattern](https://blog.domenic.me/the-revealing-constructor-pattern/). +Using the same parameter names as the language specification makes code more +uniform and easier to understand. + +Examples of **incorrect** code for this rule: ```js -new Promise(function (resolve) { ... }) -new Promise(function (resolve, reject) { ... }) +new Promise(function (reject, resolve) { /* ... */ }) // incorrect order +new Promise(function (ok, fail) { /* ... */ }) // non-standard parameter names ``` -#### Invalid +Examples of **correct** code for this rule: ```js -new Promise(function (reject, resolve) { ... }) // incorrect order -new Promise(function (ok, fail) { ... }) // non-standard parameter names +new Promise(function (resolve) { /* ... */ }) +new Promise(function (resolve, reject) { /* ... */ }) ``` -Ensures that `new Promise()` is instantiated with the parameter names -`resolve, reject` to avoid confusion with order such as `reject, resolve`. The -Promise constructor uses the -[RevealingConstructor pattern](https://blog.domenic.me/the-revealing-constructor-pattern/). -Using the same parameter names as the language specification makes code more -uniform and easier to understand. +## When Not To Use It + +If you prefer using non-standard parameter names in Promise constructors, you +can safely disable this rule. diff --git a/docs/rules/prefer-await-to-callbacks.md b/docs/rules/prefer-await-to-callbacks.md index ae61b4ba..1f38ba70 100644 --- a/docs/rules/prefer-await-to-callbacks.md +++ b/docs/rules/prefer-await-to-callbacks.md @@ -1 +1,35 @@ -# Prefer async/await to the callback pattern (prefer-await-to-callbacks) +# Prefer `async`/`await` to the callback pattern (prefer-await-to-callbacks) + +`async` and `await` are clearer and easier to understand than using callbacks. + +## Rule details + +ES2017's `async` and `await` are easier and clearer ways to deal with +asynchronous code than the callback pattern. + +Examples of **incorrect** code for this rule: + +```js +cb() +callback() +doSomething(arg, err => {}) +function doSomethingElse(cb) {} +``` + +Examples of **correct** code for this rule: + +```js +await doSomething(arg) +async function doSomethingElse() {} +yield yieldValue(err => {}) +eventEmitter.on('error', err => {}) +``` + +## When Not To Use It + +If you are not targeting an ES2017 or above environment and do not have a +shim for `async`/`await`, you should disable this rule. + +## Further Reading + +- [Making asynchronous programming easier with async and await on MDN](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await) diff --git a/docs/rules/prefer-await-to-then.md b/docs/rules/prefer-await-to-then.md index fe1ffab0..35bf3805 100644 --- a/docs/rules/prefer-await-to-then.md +++ b/docs/rules/prefer-await-to-then.md @@ -1,26 +1,13 @@ # Prefer `await` to `then()`/`catch()`/`finally()` for reading Promise values (prefer-await-to-then) -#### Valid +`async` and `await` can be clearer and easier to understand than using `then()`. -```js -async function example() { - let val = await myPromise() - val = doSomethingSync(val) - return doSomethingElseAsync(val) -} +## Rule Details -async function exampleTwo() { - try { - let val = await myPromise() - val = doSomethingSync(val) - return await doSomethingElseAsync(val) - } catch (err) { - errors(err) - } -} -``` +ES2017's `async` and `await` can be easier and clearer to deal with promises +than using `then()` and `catch()`. -#### Invalid +Examples of **incorrect** code for this rule: ```js function example() { @@ -34,6 +21,7 @@ function exampleTwo() { .catch(errors) } + function exampleThree() { return myPromise .catch(errors) @@ -44,3 +32,48 @@ function exampleFour() { .finally(cleanup) } ``` + +Examples of **correct** code for this rule: + +```js +async function example() { + let val = await myPromise() + val = doSomethingSync(val) + return doSomethingElseAsync(val) +} + +async function exampleTwo() { + try { + let val = await myPromise() + val = doSomethingSync(val) + return await doSomethingElseAsync(val) + } catch (err) { + errors(err) + } +} + +async function exampleThree() { + try { + await myPromise + } catch(error) { + errors(error) + } +} + +async function exampleFour() { + try { + await myPromise + } finally { + cleanup() + } +} +``` + +## When Not To Use It + +If you are not targeting an ES2017 or above environment and do not have a +shim for `async`/`await`, you should disable this rule. + +## Further Reading + +- [Making asynchronous programming easier with async and await on MDN](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await) diff --git a/docs/rules/valid-params.md b/docs/rules/valid-params.md index 08b66042..4cceca1c 100644 --- a/docs/rules/valid-params.md +++ b/docs/rules/valid-params.md @@ -60,5 +60,5 @@ somePromise().finally(console.log) ## When Not To Use It If you do not want to be notified when passing an invalid number of arguments to -a Promise function (for example, when using a typechecker like Flow), you can -safely disable this rule. +a Promise function (for example, when using a type checker like Flow or +Typescript), you can safely disable this rule.