19

node.js将回调函数嵌套,用promise改造成async/await顺序执行:异常处理和返回多个参...

 4 years ago
source link: http://ourjs.com/detail/k6rmrbnv9iin
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

回调嵌套

在ES6语法出现之前,如果想要若干个异步过程按顺序执行,则需要使用回调嵌套,比如这里有个step函数,执行需要一定的时间:

var step = function(isError, cb) {
 setTimeout(function() {
   console.log(new Date())
   cb && cb(isError && new Error('step Error'), isError)
 }, 1000)
}

如果想要执行两次step,并且必须按顺序个条一条执行,在以前一般要使用回调嵌套:

var test = function() {
 step(0, function(err, isError1) {
   if (err) {
     console.log(err)
   }

   step(0, function(err, isError2) {
     if (err) {
       console.log(err)
     }

   })
 })
}

用async/await

在ES6语法中,可以通过async/await将上面的回调函数按顺序执行。

首先将原来的方法 promisify 化,引用 util 库将 step 函数即可:

const util = require('util')

var stepAsync = util.promisify(step)

然后用 async/await 顺序执行,注意 await 只能在 async 函数中使用

var test = async function() {
 let result1 = await stepAsync(0)
 let result2 = await stepAsync(0)
 console.log(result1, result2)
}

test()

结果:

2020-02-18T07:54:01.081Z
2020-02-18T07:54:01.081Z
0 0

其实 util.promisify 只是将函数封装成了Promise对象,实现并不复杂,不过使用promisify有两个前提条件

1. Error first 原则: 即你在调用回调函数时,第一个必须为error

2. Callback last 原则: 即在往函数传参数时,最后一个参数是回调函数

异常处理

在 async/await 中使用 try/ catch 捕获处理异常

var test = async function() {
 try {
   let result1 = await stepAsync(0)
   let result2 = await stepAsync(1)
   console.log(result1, result2)
 } catch(e) {
   console.log(e)
 }
}

test()

结果:

2020-02-18T07:54:01.081Z
2020-02-18T07:54:01.081Z
Error: step Error
 at Timeout._onTimeout (testAwait.js:59:25)
 at ontimeout (timers.js:475:11)
 at tryOnTimeout (timers.js:310:5)
 at Timer.listOnTimeout (timers.js:270:5)

多参数返回

估计大家已经看到了,类似这样的调用,只能接收一个参数:

 let result1 = await stepAsync(0)

目前在JavaScript还没有一种语法可以在一行语法中同时给两个变量分别赋值,期待在以后的JS版本里有所改进。所以如果你的方法中要返回一个以上的参数,可以将其变成成数组或对象:

比如,下面是使用数组返回的例子:

 
var step = function(isError, cb) {
 setTimeout(function() {
 console.log(new Date())
 cb && cb(isError && new Error('step Error'), [ isError, Date.now() ])
 }, 1000)
}

var stepAsync = util.promisify(step)

var test = async function() {
 try {
 let [ result1, time1 ] = await stepAsync(0)
 let [ result2, time2 ] = await stepAsync(0)
 console.log(result1, time1, result2, time2)
 } catch(e) {
 console.log(e)
 }
}

test()

执行:

$ node testAwait.js
2020-02-18T08:10:31.328Z
2020-02-18T08:10:32.365Z
0 1582013431334 0 1582013432365

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK