JS Promise使用注意事项

前言

对于js而言,我们平时使用promise情况是十分常见的 ,然而有些地方并没有很好地使用,这篇文章介绍常见的promise不规范示范和正确使用方式。

一、finally使用

通常开发过程中,我们页面都有loading,使用Promise前开启loading,结束的时候关闭loading。但有些小伙伴会在then和catch里面结束,这样不够优雅,其实最好是在finally里面结束。
正确示范:

  let isLoading = true
  const result = await promiseSuccess()
    .finally(() => {
    
    
      isLoading = false
    })

二、错误捕获

错误捕获可以使用.catch 和try catch,二者是由区别的,最大区别是try catch只要捕获到一个错误就会中断后续代码,但.catch不会,需要结合resolve结果来中断代码。

现在我们拥有2个方法

  • promiseSuccess(),该方法100%返回resolve(true)
  • promiseFail(),该方法100%返回reject(new Error("出错了"))
/** promise成功 */
function promiseSuccess() {
    
    
  return new Promise((resolve) => {
    
    
    resolve(true)
  })
}

/** promise失败 */
function promiseFail(errorStr = '出错了') {
    
    
  return new Promise((resolve, reject) => {
    
    
    reject(new Error(errorStr))
  })
}

2.1 .cath捕获

  console.log(1)

  await promiseSuccess().catch((error) => {
    
    
    console.log(error)
  })
  console.log(2)

  await promiseFail().catch((error) => {
    
    
    console.log(error)
  })
  console.log(3)
  • 执行上述代码,结果是
1
2
Error: 出错了
3

通常我们是发生错误的时候需要中断代码执行,那么需要结合resolve结果来判断是否要中断代码,正确写法是

  console.log(1)

  const result1 = await promiseSuccess().catch((error) => {
    
    
    console.log(error)
  })
  if (!result1) return
  console.log(2)

  const result2 = await promiseFail().catch((error) => {
    
    
    console.log(error)
  })
  if (!result2) return
  console.log(3)
  • 执行上述代码,结果是
1
2
Error: 出错了

2.2 try catch捕获

上述代码好像有点啰嗦,所以我们可以用try catch,正确代码:

  try {
    
    
    console.log(1)
    const result1 = await promiseSuccess()
    console.log(2)
    const result2 = await promiseFail()
    console.log(3)
  } catch (error) {
    
    
    console.log(error)
  }
  • 执行上述代码,结果是
1
2
Error: 出错了

三、Promise方法内使用return

首先,Promise方法内使用return是不建议的,如果有用eslint,那么会提示 no-return-await,我们看看如果用return会由什么结果

3.1 前置return

  • 修改方法promiseSuccess,会在resolve前执行return
/** promise成功 */
function promiseSuccess() {
    
    
  return new Promise((resolve) => {
    
    
    return 'return'
    resolve(true)
  })
}
  • 测试程序
console.log(1)

const result = await promiseSuccess().catch((error) => {
    
    
  console.log(error)
})
console.log('result', result)
if (!result) return

console.log(2)
  • 执行上述代码,结果是
1
  • 原因分析:由于promiseSuccess没有执行到resolve,所以await一直在等待,程序不会往下处理。

3.2 后置return

  • 修改方法promiseSuccess,会在resolve后执行return
/** promise成功 */
function promiseSuccess() {
    
    
  return new Promise((resolve) => {
    
    
    resolve(true)
    return 'return'
  })
}
  • 测试程序设上面一致
  • 执行上述代码,结果是
1
result true
2
  • 原因分析:await只会获取resolve结果,里面的return值并没有影响

四 await后不跟promise

await 不仅仅用于等 Promise 对象,它可以等任意表达式的结果,所以,await 后面实际是可以接普通函数调用或者直接量的。等待这个操作完成才能进行await语句下面的程序。

await后面跟的不是promise对象,会将其他值包装成一个promise对象

(async function(){
    
    
  const res = await 400 //Promise.resolve(400)
  console.log(res) //400
})()

await后面跟普通函数,接收return值(可以是异步函数)

(async function(){
    
    
	const res = await getData(false) // 这里会等待getData函数执行完毕,接收return值
})()

async function getData(param){
    
    
	if(param) return 1
	const res = await otherFun()
	return res
}

四 no-async-promise-executor

不建议将 async 函数传递给 new Promise 的构造函数;
如果下面代码,如果有用eslint会提示 no-async-promise-executor,原因是async本来是异步的,就无必要嵌套在Promise里面了。

  • 代码示范
// 错误示范:
function promiseTest() {
    
    
  return new Promise(async (resolve) => {
    
    
    const result = await promiseSuccess()
    resolve(result)
  })
}

// 正确示范1:
async function promiseTest() {
    
    
  const result = await promiseSuccess()
  return result
}

// 正确示范2,如果硬要使用Promise,那么可以这样:
async function promiseTest() {
    
    
  const result = await promiseSuccess()
  return new Promise((resolve) => {
    
    
    resolve(result)
  })
}
  • 使用方式都一样
const result1 = await promiseTest().catch((error) => {
    
    
  console.log(error)
})
console.log('result1', result1)

五、no-await-in-loop

不建议在循环里使用 await,有这种写法通常意味着程序没有充分利用 JavaScript 的事件驱动。
通常情况下可以使用Promise.all 代替。

  • 示范代码:
// 错误示范:
async function foo(things) {
    
    
  const results = [];
  for (const thing of things) {
    
    
    results.push(await bar(thing));
  }
  return baz(results);
}

// 正确示范:
async function foo(things) {
    
    
  const results = [];
  for (const thing of things) {
    
    
    results.push(bar(thing));
  }
  return baz(await Promise.all(results));
}

但是,如果每一次循环都需要改变数据,并且这个数据会带入到下次循环里,这种情况是可以使用循环里嵌套await的!

猜你喜欢

转载自blog.csdn.net/iamlujingtao/article/details/129177624