优雅的使用 async与 await 处理 promise 的 reject

问题

javaScript 中有很多异步操作,比如ajax获取数据。

假如有一个获取表格数据的请求,基于这个请求获取一个数据的详情

axios.get('/api/table_list')
	.then(res=>{
		let id = res[0].tableId
		axios.get('/api/table_detail?id='+id)
			.then(res=>{
				randerToView(res)
			})
			.catch(err=>handelErr(err))
	})
	.catch(err=>handelErr(err))

function randerToView(object){}

这样的代码读起来很费力,写起来也不友好,好在有asyncawait,可以让代码可读性得到提升

(asycn ()=>{
	let res = await axios.get('/api/table_list')
	let  id = res[0].tableId
	let detail = await  axios.get('/api/table_detail?id='+id)
	randerToView(detail )
})()

但是这样写也有个问题,就是我们不能在异步发生错误的时候,捕捉到该错误,因此,代码应该放在try{}catch(){}语句中

try{
	let res = await axios.get('/api/table_list')
	let  id = res[0].tableId
	let detail = await  axios.get('/api/table_detail?id='+id)
	randerToView(detail )
}catch(err){
	handelErr(err)
}

这段代码看上去还 ok,但是写得多了,仔细想想,这个 try...catch...感觉也不是很优雅。难道不能有一种解决方案来满足程序员的小洁癖吗?

分析

假如我们把axios.get('/api/table_list')打印出来,会发现它是一个Promise,而await只能拿到resolve状态,因此对于错误是无能无力的。

try...catch...是捕获其内部的任何错误,因此可以 catch 到reject状态。

所以我们是不是可以尝试自己实现一个方法,先处理 Promise 的 Error 呢?然后将捕获的 Error 和正常的数据放进另一个 Promise 的 resolve 中,再传递给 await 。

实现

export handlerPromise = (promise) => promise.then(data => [null, data]).catch(err => [err])

验证

在程序中,处理删除是非常谨慎的,通常我们要弹出一个确认框提示用户是否要删除数据。

elementUI 中的 Message 模块提供了完善的实现。

每一个页面可能都有需要用户删除的数据,那我们就可以抽取一个确认弹框,作为公共的方法。

// val 是要删除的数据,type 为 Array
export const delDialog = (val) =>
  new Promise((resolve, reject) => {
    if (!val.length) {
      Message.info('请选择要删除的数据')
      reject(new Error())
    } else {
      MessageBox.confirm('将删除选中的数据,确定删除吗?', '提示', {
        cancelButtonText: '取消',
        confirmButtonText: '确定',
        type: 'warning'
      }).then(() => {
        resolve(val)
      }).catch((action) => {
        reject(action)
      })
    }
  })

在需要使用的页面引入,就可以了。

import { delDialog , handlerPromise } from '@/utils/del'

...

methods:{
	handleRemove(){
		let [dialogErr, res] = await handlerPromise(delDialog (this.multipleSelection))
		//因为ajax错误已经在顶层做了捕捉和提示用户,所以在这里直接 return 就可以了
		if(dialogErr) return
		let [deleteErr, res] = await handlerPromise(tableDelete(res))
		if(!deleteErr) this.$message.success('删除成功')
	}
}

猜你喜欢

转载自blog.csdn.net/zhai_865327/article/details/106863026
今日推荐