每个人都应该知道的常见JavaScript承诺



朋友们,美好的一天!

我向您介绍Apal Shah文章的翻译, “每个初学者都应该知道并避免的常见Javascript Promise错误

每个人都应该知道的常见JavaScript承诺


在学习JavaScript和Promise时,我想了解这些错误。

每当有开发人员打电话给我并抱怨他的代码无法正常工作或执行缓慢时,我首先要注意这些错误。 当我4年前开始编程时,我并不了解它们,并且习惯于忽略它们。 但是,在分配给一个在几分钟内处理大约一百万个请求的项目之后,我别无选择,只能优化我的代码(因为我们达到了无法进一步垂直扩展的水平)。

因此,在本文中,我想谈谈在JS中使用promise时最常见的错误,许多人没有注意。

错误1:在Promise中使用try / catch块


在promise中使用try / catch块是不切实际的,因为如果您的代码引发错误(在promise内部),则promise本身的错误处理程序将拦截该错误。

这是关于什么的:
new Promise((resolve, reject) => { try { const data = someFunction() //   resolve() } catch(e) { reject(e) } }) .then(data => console.log(data)) .catch(error => console.log(error)) 

相反,让代码处理承诺之外的错误:
 new Promise((resolve, reject) => { const data = someFunction() //   resolve(data) }) .then(data => console.log(data)) .catch(error => console.log(error)) 

除非如下所述,否则它将始终有效。

错误2。在Promise中使用异步函数


使用异步功能时,Promise中会出现一些不愉快的副作用。

假设您决定执行一些异步任务,在诺言中添加关键字“ async”,并且您的代码将引发错误。 但是,现在您无法使用.catch()或await处理此错误:
 //       new Promise(async() => { throw new Error('message') }).catch(e => console.log(e.message)) //        (async() => { try { await new Promise(async() => { throw new Error('message') }) } catch(e) { console.log(e.message) } })(); 

每当我在promise中遇到异步函数时,我都会尝试将它们分开。 我在10个案例中有9个得到了它。 但是,这并不总是可能的。 在这种情况下,您别无选择,只能在promise中使用try / catch块(是的,这与第一个错误相矛盾,但这是唯一的出路):
 new Promise(async(resolve, reject) => { try { throw new Error('message') } catch(error) { reject(error) } }).catch(e => console.log(e.message)) //   async/await (async() => { try { await new Promise(async(resolve, reject) => { try { throw new Error('message') } catch(error) { reject(error) } }) } catch(e) { console.log(e.message) } })(); 

错误3。忘记.catch()


这是直到测试开始您都不怀疑存在的错误之一。 或者,如果您是不相信测试的无神论者,那么您的代码肯定会在生产环境中崩溃。 因为生产严格遵循墨菲定律 ,该定律指出:“任何可能出错的地方都会出错”(您可以翻译为:“如果某些地方可能出错,那么它将发生”;俄语中的类比是“卑鄙的法律”) -大约

为了使代码更加优雅,您可以将promise封装在try / catch中,而不是使用.then()。Catch()。

错误4。请勿使用Promise.all()


Promise.all()是您的朋友。

如果您是专业的开发人员,您可能理解我想说的话。 如果您有多个彼此不依赖的承诺,则可以同时执行它们。 默认情况下,promise是并行执行的,但是,如果您需要顺序执行它们(使用await),则将花费很多时间。 Promise.all()可以大大减少延迟:
 const {promisify} = require('util') const sleep = promisify(setTimeout) async function f1() { await sleep(1000) } async function f2() { await sleep(2000) } async function f3() { await sleep(3000) } //   (async() => { console.time('sequential') await f1() await f2() await f3() console.timeEnd('sequential') //  6  })(); 

现在有了Promise.all():
 (async() => { console.time('concurrent') await Promise.all([f1(), f2(), f3()]) console.timeEnd('concurrent') //  3  })(); 

错误5。Promise.race()的使用不当


Promise.race()并不总是使您的代码更快。

可能看起来很奇怪,但确实如此。 我并不是说Promise.race()是一种无用的方法,但是您必须清楚地理解为什么要使用它。

例如,您可以在解决任何承诺后使用Promise.race()运行代码。 但这并不意味着遵循承诺的代码的执行将在其中一个承诺解决之后立即开始。 Promise.race()将等待所有promise解析,然后才释放流:
 const {promisify} = require('util') const sleep = promisify(setTimeout) async function f1() { await sleep(1000) } async function f2() { await sleep(2000) } async function f3() { await sleep(3000) } (async() => { console.time('race') await Promise.race([f1(), f2(), f3()]) })(); process.on('exit', () => { console.timeEnd('race') //  3 ,    ! }) 

错误6。滥用承诺


承诺会使代码变慢,因此请不要滥用它们。

通常,您必须看到开发人员使用较长的.then()链来使他们的代码看起来更好。 由于该链变得太长,您将没有时间眨眼。 为了从视觉上验证这种情况的负面后果,有必要(我将进一步偏离原文,以便比文章中更详细地描述该过程-大约Trans):

1)创建一个具有以下内容的script.js文件(带有额外的承诺):
 new Promise((resolve) => { //  ,    const user = { name: 'John Doe', age: 50, } resolve(user) }).then(userObj => { const {age} = userObj return age }).then(age => { if(age > 25) { return true } throw new Error('Age is less than 25') }).then(() => { console.log('Age is greater than 25') }).catch(e => { console.log(e.message) }) 

2)打开命令行(对于Windows用户:在包含所需文件的文件夹中打开命令行,按住Shift,单击鼠标右键,选择“打开命令窗口”),使用以下命令运行script.js(必须安装Node。 js):
 node --trace-events-enabled script.js 

3)Node.js使用脚本在文件夹中创建一个日志文件(在我的情况下为node_trace.1.txt);

4)打开Chrome(因为它只能在其中使用),在地址栏中输入“ chrome://跟踪”;

5)点击Load,加载Node.js创建的日志文件;

6)打开Promise选项卡。

我们看到如下内容:


绿色块是承诺,每个块都需要几毫秒才能完成。 因此,承诺越多,履行的时间就越长。

我们重写script.js:
 new Promise((resolve, reject) => { const user = { name: 'John Doe', age: 50, } if(user.age > 25) { resolve() } else { reject('Age is less than 25') } }).then(() => { console.log('Age is greater than 25') }).catch(e => { console.log(e.message) }) 

重复“跟踪”。

我们看到以下内容:


绿色块(承诺)较少,这意味着代码执行时间已减少。

因此,仅在需要执行一些异步代码时,才应使用多个Promise。

谢谢您的关注。 周末愉快! 我将很高兴收到任何评论。

Source: https://habr.com/ru/post/zh-CN484466/


All Articles