返回

JS 中 Promise 编写技巧~

前端

对于一个合格的前端工程师来说,Promise 那可是咱 Javascript 中的浪漫,每天都用,虽然每天都用,但是小伙伴们不确定自己对 Promise 的了解是否完整?你是不是有时候觉得一些地方有点懵,但是又不确定这是因为自己粗心,还是 Promise 本身就在使用上有些盲区呢?

1. 不要在 Promise 中使用 catch 来处理同步错误

catch 块是用来处理异步错误的。如果在 Promise 中使用 catch 来处理同步错误,就会导致代码难以理解和维护。例如:

function foo() {
  throw new Error('This is a synchronous error');
}

foo().catch(err => {
  console.log(err.message);
});

这段代码会导致错误消息 'This is a synchronous error' 被打印两次。一次是通过 throw 语句,另一次是通过 catch 块。

为了避免这种问题,应该在同步代码中使用 try...catch 语句来处理同步错误。例如:

try {
  foo();
} catch (err) {
  console.log(err.message);
}

2. 不要在 Promise 中返回一个新的 Promise

如果在 Promise 中返回一个新的 Promise,就会导致代码难以理解和维护。例如:

function foo() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('Hello world!');
    }, 1000);
  });
}

foo().then(result => {
  console.log(result);
});

这段代码会导致 'Hello world!' 被打印两次。一次是通过 resolve 函数,另一次是通过 then 方法。

为了避免这种问题,应该在 Promise 中直接返回一个值,而不是返回一个新的 Promise。例如:

function foo() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('Hello world!');
    }, 1000);
  });
}

foo().then(result => {
  console.log(result);
}).then(result => {
  console.log(result);
});

3. 不要在 Promise 中使用 finally 块来处理错误

finally 块是用来处理 Promise 的最终状态的。如果在 Promise 中使用 finally 块来处理错误,就会导致代码难以理解和维护。例如:

function foo() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(new Error('This is an error'));
    }, 1000);
  });
}

foo().then(result => {
  console.log(result);
}).catch(err => {
  console.log(err.message);
}).finally(() => {
  console.log('This will always be called');
});

这段代码会导致 'This is an error' 被打印两次。一次是通过 reject 函数,另一次是通过 finally 块。

为了避免这种问题,应该在 Promise 中直接处理错误,而不是在 finally 块中处理错误。例如:

function foo() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(new Error('This is an error'));
    }, 1000);
  });
}

foo().then(result => {
  console.log(result);
}).catch(err => {
  console.log(err.message);
});

4. 不要在 Promise 中使用竞争条件

竞争条件是指两个或多个并发执行的进程试图访问同一个共享资源,从而导致数据不一致的情况。在 Promise 中,竞争条件可能会导致意外的结果。例如:

function foo() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('Hello world!');
    }, 1000);
  });
}

function bar() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('Goodbye world!');
    }, 1000);
  });
}

Promise.all([foo(), bar()]).then(results => {
  console.log(results);
});

这段代码会导致 ['Goodbye world!', 'Hello world!'] 被打印,而不是 ['Hello world!', 'Goodbye world!']。这是因为 bar() 函数的执行速度比 foo() 函数的执行速度快,导致 bar() 函数的返回值先被打印出来。

为了避免这种问题,应该使用 Promise.race() 方法来处理竞争条件。Promise.race() 方法会返回最先完成的 Promise 的返回值。例如:

function foo() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('Hello world!');
    }, 1000);
  });
}

function bar() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('Goodbye world!');
    }, 1000);
  });
}

Promise.race([foo(), bar()]).then(result => {
  console.log(result);
});

这段代码会导致 'Hello world!' 被打印,而不是 'Goodbye world!'。这是因为 foo() 函数的执行速度比 bar() 函数的执行速度快,导致 foo() 函数的返回值先被打印出来。

5. 不要在 Promise 中使用不必要的代码

Promise 中不必要的代码会增加代码的复杂性,并使代码难以理解和维护。例如:

function foo() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('Hello world!');
    }, 1000);
  });
}

foo().then(result => {
  console.log(result);
}).then(result => {
  console.log(result);
}).then(result => {
  console.log(result);
});

这段代码会导致 'Hello world!' 被打印三次。这是因为 then() 方法会返回一个新的 Promise,而新的 Promise 也会调用 then() 方法。

为了避免这种问题,应该在 Promise 中使用 finally() 方法来处理最终状态。finally() 方法不会返回一个新的 Promise,因此不会导致不必要的代码执行。例如:

function foo() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('Hello world!');
    }, 1000);
  });
}

foo().then(result => {
  console.log(result);
}).finally(() => {
  console.log('This will be called regardless of the Promise state');
});

这段代码会导致 'Hello world!' 被打印一次,然后 'This will be called regardless of the Promise state' 被打印一次。