Reprint--Several recommended practices for JavaScript asynchronous code

The wind elegant 2022-08-06 08:29:09 阅读数:17

reprint--severalreprintrecommendedpracticesjavascript

Today I would like to recommend a few to you JavaScript Recommended practices for asynchronous code,Each scenario has a corresponding eslint 规则,You can choose to configure.

no-async-promise-executor

不建议将 async 函数传递给 new Promise 的构造函数.

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

首先,你在 Promise in the constructor to use async ,Then pack Promise Maybe it's not necessary.另外,如果 async 函数抛出了异常,新构造的 promise instance does not reject ,Then this error cannot be caught.

no-await-in-loop

Not recommended for use in the loop await,Writing this way usually means that the program is underutilized JavaScript 的事件驱动.

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

It is recommended to change these asynchronous tasks to concurrent execution,This can greatly improve the execution efficiency of the code.

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

no-promise-executor-return

不建议在 Promise 构造函数中返回值,Promise The value returned in the constructor is not usable,and the return value will not affect Promise 的状态.

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

The normal practice is to pass the return value to resolve,If there is an error, pass it to reject.

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

require-atomic-updates

It is not recommended to put the assignment and operation await 组合使用,This can lead to race conditions.

看看下面的代码,你觉得 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);

totalPosts 会打印 3 或 5,并不会打印 8,You can try it yourself in your browser.

The problem is with reading totalPosts 和更新 totalPosts there is a time interval between.This results in a race condition,When the value is updated in a separate function call,Updates are not reflected in the current function scope.因此,Both functions will add their results to totalPosts 的初始值0.

The right way to avoid race conditions:

// 
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

防止回调地狱,Avoid a lot of deep nesting:

/* 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);

Callback hell makes code hard to read and maintain,It is recommended to refactor the callbacks as Promise and use modern async/await 语法.

no-return-await

It is not necessary to write when returning asynchronous results await ,If you are waiting for a Promise,and then immediately return to it,这可能是不必要的.

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

从一个 async All values ​​returned by the function are contained in a Promise 中,you can just return this Promise.

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

当然,也有个例外,如果外面有 try...catch 包裹,删除 await Can't catch exception,在这种情况下,It is recommended to clarify the intention,assign the result to a variable on a different row.

// 
async () => {
  try {
    return await getUser(userId);
  } catch (error) {
    // Handle getUser error
  }
}
// 
async () => {
  try {
    const user = await getUser(userId);
    return user;
  } catch (error) {
    // Handle getUser error
  }
}

prefer-promise-reject-errors

建议在 reject Promise 时强制使用 Error 对象,This makes it easier to trace the error stack.

// 
Promise.reject('An error occurred');
// 
Promise.reject(new Error('An error occurred'));

node/handle-callback-err

强制在 Node.js In the asynchronous callback of exception handling.

// 
function callback(err, data) {
  console.log(data);
}
// 
function callback(err, data) {
  if (err) {
    console.log(err);
    return;
  }
  console.log(data);
}

在 Node.js 中,Usually the exception is passed as the first parameter to the callback function.Forgetting to handle these exceptions can lead to unpredictable problems with your application.

If the first parameter of the function is named err will trigger this rule,你也可以去 .eslintrc Custom exception parameter name in the file.

node/no-sync

Not recommended where asynchronous alternatives exist Node.js 核心 API Synchronous method used in.

// 
const file = fs.readFileSync(path);
// 
const file = await fs.readFile(path);

Node.js 中对 I/O Operation using a synchronous method blocks the event loop.大多数场景下,执行 I/O Using async methods when operating is a better choice.

@typescript-eslint/await-thenable

不建议 await 非 Promise function or value.

// 
function getValue() {
  return someValue;
}
await getValue();
// 
async function getValue() {
  return someValue;
}
await getValue();

@typescript-eslint/no-floating-promises

建议 Promise Additional code for exception handling.

// 
myPromise()
  .then(() => {});
// 
myPromise()
  .then(() => {})
  .catch(() => {});

form a good habit,Always do exception handling!

@typescript-eslint/no-misused-promises

不建议将 Promise pass to places where they are not intended to be processed,例如 if 条件.

// 
if (getUserFromDB()) {}
//  
if (await getUserFromDB()) {}

It is more recommended to extract a variable to improve the readability of the code.

//  
const user = await getUserFromDB();
if (user) {}
版权声明:本文为[The wind elegant]所创,转载请带上原文链接,感谢。 https://qdmana.com/2022/218/202208060818127811.html