首页 > 其他分享 >帮助编写异步代码的ESLint规则

帮助编写异步代码的ESLint规则

时间:2024-01-21 22:35:59浏览次数:26  
标签:异步 const 规则 await Promise ESLint 编写 async eslint

调试 JavaScript 中的异步代码有时就像在雷区中穿梭。你不知道 console.log 会在何时何地打印出来,也不知道代码是如何执行的。

你很难正确构造异步代码,使其按照你的意图以正确的顺序执行。

如果在编写异步代码时能得到一些指导,并在即将出错时收到一条有用的信息,那岂不更好?

幸运的是,在将错误推向生产环境之前,我们有一些规则来捕捉这些错误。以下是一份经过编译的linting规则列表,可为你在 JavaScript 和 Node.js 中编写异步代码提供具体帮助。

即使你最终没有在项目中使用这些规则,阅读它们的说明也会让你更好地理解异步代码,并提高你的开发技能。

ESLint异步代码规则

ESLint 默认提供以下规则。将它们添加到 .eslintrc 配置文件中即可启用。

no-async-promise-executor

该规则不允许将async函数传递给new Promise构造函数。

// ❌
new Promise(async (resolve, reject) => {});

// ✅
new Promise((resolve, reject) => {});

虽然从技术上讲,向 Promise 构造函数传递异步函数是有效的,但出于以下两个原因,这样做通常是错误的。首先,如果异步函数抛出错误,错误将丢失,不会被新构造的 Promise 拒绝。其次,如果在构造函数内部使用了 await,那么外层的 Promise 可能就没有必要了,可以将其删除。

no-await-in-loop

该规则不允许在循环内使用await

在对可迭代对象的每个元素进行操作并等待异步任务时,往往表明程序没有充分利用 JavaScript 的事件驱动架构。通过并行执行任务,可以大大提高代码的效率。

// ❌
for (const url of urls) {
  const response = await fetch(url);
}

// ✅
const responses = [];
for (const url of urls) {
  const response = fetch(url);
  responses.push(response);
}

await Promise.all(responses);

如果你想按顺序运行任务,我建议你使用行内注释暂时禁用该规则:// eslint-disable-line no-await-in-loop

no-promise-executor-return

该规则不允许在 Promise 构造函数中返回值。

// ❌
new Promise((resolve, reject) => {
  return result;
});

// ✅
new Promise((resolve, reject) => {
  resolve(result);
});

在 Promise 构造函数中返回的值不能使用,也不会对 promise 产生任何影响。应将该值传递给resolve,如果发生错误,则调用 reject 并告知错误信息。

该规则不会阻止你在 Promise 构造函数中的嵌套回调内返回值。请务必使用 resolvereject 来结束promise。

require-atomic-updates

该规则不允许将赋值与 await 结合使用,否则会导致竞赛条件。

请看下面的示例,你认为 totalPosts 的最终值会是多少?

// ❌
let totalPosts = 0;

async function getPosts(userId) {
  const users = [{ id: 1, posts: 5 }, { id: 2, posts: 3 }];
  await sleep(Math.random() * 1000);
  return users.find((user) => user.id === userId).posts;
}

async function addPosts(userId) {
  totalPosts += await getPosts(userId);
}

await Promise.all([addPosts(1), addPosts(2)]);
console.log('Post count:', totalPosts);

也许你已经感觉到这是一个骗人的问题,答案不是 8。没错,totalPosts 打印的是 5 或 3。自己在浏览器中试试吧。

问题在于读取和更新 totalPosts 之间存在时间差。这就造成了一个竞赛条件,当值在单独的函数调用中更新时,更新不会反映在当前函数的作用域中。因此,这两个函数都将其结果添加到 totalPosts 的初始值 0 中。

要避免这种竞赛条件,应确保在更新变量的同时读取变量。

// ✅
let totalPosts = 0;

async function getPosts(userId) {
  const users = [{ id: 1, posts: 5 }, { id: 2, posts: 3 }];
  await sleep(Math.random() * 1000);
  return users.find((user) => user.id === userId).posts;
}

async function addPosts(userId) {
  const posts = await getPosts(userId);
  totalPosts += posts; // variable is read and immediately updated
}

await Promise.all([addPosts(1), addPosts(2)]);
console.log('Post count:', totalPosts);

max-nested-callbacks

该规则强制限制回调的最大嵌套深度。换句话说,该规则可防止回调地狱!

/* eslint max-nested-callbacks: ["error", 3] */

// ❌
async1((err, result1) => {
  async2(result1, (err, result2) => {
    async3(result2, (err, result3) => {
      async4(result3, (err, result4) => {
        console.log(result4);
      });
    });
  });
});

// ✅
const result1 = await asyncPromise1();
const result2 = await asyncPromise2(result1);
const result3 = await asyncPromise3(result2);
const result4 = await asyncPromise4(result3);
console.log(result4);

深度嵌套会使代码难以阅读,更难以维护。在编写 JavaScript 异步代码时,将回调重构为promise,并使用现代的 async/await 语法。

no-return-await

该规则不允许不必要的return await

// ❌
async () => {
  return await getUser(userId);
}

// ✅
async () => {
  return getUser(userId);
}

由于async函数返回的所有值都已封装在 promise 中,因此等待 promise 并立即返回是不必要的。因此,你可以直接返回 promise。

当周围有 try...catch 语句时,这条规则会出现例外。移除 await 关键字会导致不捕获拒绝的promise。在这种情况下,我建议你将结果赋值给另一行的变量,以明确意图。

// 

标签:异步,const,规则,await,Promise,ESLint,编写,async,eslint
From: https://www.cnblogs.com/chuckQu/p/17978582

相关文章

  • Make简介和Makefile编写规则
    1.什么是make?(1)make定义make工程管理器,是Linux下自动编译管理器;为了维护C程序文件,防止不必要的重新编译;对于维护具有相互依赖关系的文件特别有用,对文件和命令的联系提供一套编码方法自动化编译。运行环境,需要一个命令程序make和一个文本文件makefile。例......
  • 线程异步操作
    目录什么是C++中的异步操作?std::async异步调用函数什么是C++中的异步操作?在C++中,异步操作是指在程序执行期间,可以同时执行多个任务,而无需等待前一个任务完成。这种并发执行的方式可以提高程序的性能和响应速度。C++中的异步操作通常通过多线程或异步任务来实现。使用std::asyn......
  • python 异步回调传递参数 warning cell-var-from-loop
    warning:cell-var-from-loopbing解释foriinrange(10):f=lambdai:iprint(f())Thewarningmessagecell-var-from-loopisemittedbyPylint,aPythoncodeanalysistool.Thiswarningisraisedwhenavariableisdefinedinsidealoopandused......
  • 如何使用Markdown编写笔记
    Markdown是什么?Markdown是一种轻量级标记语言,创始人为约翰·格鲁伯(JohnGruber)。它允许人们使用易读易写的纯文本格式编写文档,然后转换成有效的XHTML(或者HTML)文档。这种语言吸收了很多在电子邮件中已有的纯文本标记的特性。由于Markdown的轻量化、易读易写特性,并且对于图片......
  • Woodpecker CI 设计分析|一个 Go 编写的开源持续集成引擎
    一、前言大家好,这里是白泽。随着Go语言在云原生领域大放异彩,开发者逐渐将目光转移到了这门语言上,而容器则是云原生时代最核心的载体。《WoodpeckerCI设计分析》系列文章将分析开源CI引擎Woodpecker的架构设计,探究Go协程是如何支持由Workflow定义的大量Task的频繁创建......
  • 用c语言编写一个简单的学生信息的录入查询
    include<stdio.h>include<string.h>structstudent{charname[20];//使用结构体对姓名年龄分数进行赋值intage;intscore;}st[3]={{"jack",18,80},{"Rose",17,85},{"tom",19,60}};intmain(intargc,charconst*argv[]){c......
  • Qt如何调用VS编写的动态链接库(dll文件)
     下面是我在VS编译器上写的一个简单的dll文件,关于dll文件如何编写,我就不再赘述了。.h文件#ifndef_MYDLL_H#define_MYDLL_H#ifdefMYDLL_EXPORTS#defineMYDLL_API__declspec(dllexport)#else#defineMYDLL_API__declspec(dllimport)#endifextern"C"MYDLL_......
  • js 异步函数策略
    因为简单实用,所以异步函数很快成为JavaScript项目使用最广泛的特性之一。不过,在使用异步函数时,还是有些问题要注意。实现sleep()很多人在刚开始学习JavaScript时,想找到一个类似Java中Thread.sleep()之类的函数,好在程序中加入非阻塞的暂停。以前,这个需求基本上都通过set......
  • js 异步函数的返回值
    函数可以得到它返回的期约:asyncfunctionfoo(){console.log(1);return3;}//给返回的期约添加一个解决处理程序foo().then(console.log);console.log(2);//1//2//3当然,直接返回一个期约对象也是一样的:asyncfunctionfoo(){console.log(1);returnProm......
  • 池和异步回调机制
    池【1】概念池是用来保证计算机硬件安全的情况下,最大限度的利用计算机资源,降低了程序的运行效率,但是保证了计算机硬件的安全池(Pool)的概念在计算机科学和软件工程中常被用于资源管理,尤其是在多线程或并发编程中。池是一种管理和优化资源分配的机制,它事先分配一定数量的资源(......