2019-6-13awaitcall

Jun 13, 2019

js/ts 如何享受async 舒适下远离try{}catch{}

1
2
3
4
5
6
7
async login () {
try {
await userLogin()
} catch (e => {
this.$message.error(e)
})
}

async 带来了很大的方便,但是try/catch 却破坏了写作的美感。

我们想要这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const callAsync, { call } = require('awaitCall')

async login () {
// callAsync allows promise as input
const [err, response] = await callAsync(userLogin())
if (err) return this.$message.eror(err)
// user login successfully
}

async writeFile (input) {
// call allows any function which can be accepted by require('util').promisify with a promise output
const [err, res] = await call(fs.write, input)
if (err) throw err
// fs.write successfully
const [openErr, openRes] = await call(fs.open, 'a.txt', 'r+', 0o654)
// ...
}

以上提供了两个方法callAsync、call。

callAsync 允许输入promise 之后flattern 回调。

call 支持输入function,帮助用户转化为promise 之后flattern 回调(function 必须支持require('util').promisify 转化为promise 类型)。

核心代码不多,支持JS、Typescript

awaitCall.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const util = require('util')

export function callAsync(promise) {
return promise
.then((data) => [null, data])
.catch(err => [err, null])
}

export function call(func, ...args) {
const promise = util.promisify(func).call(this, ...args)
if (typeof promise !== 'object') {
return Promise.reject('func should match util.promisify')
}
return callAsync(promise)
}

export default callAsync

awaitCall.d.ts

1
2
3
4
export module callAsync {
export function callAsync<T, U = any>(promise: Promise<T>): Promise<[U | null, T | null]>
export function call(func: Function, ...args: any[]): Promise<any>
}

Typescript 完整实现

awaitCall.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import util from 'util'

export function callAsync<T, U = any>(promise: Promise<T>): Promise<[U | null, T | null]> {
return promise
.then<[null, T]>((data: T) => [null, data])
.catch<[U, null]>(err => [err, null])
}

export function call(func: Function, ...args: any[]): Promise<any> {
const promise = util.promisify(func).call(this, ...args)
// promise is object type
if (typeof promise !== 'object') {
return Promise.reject('func should match util.promisify')
}
const _promise = promise as Promise<any>
return callAsync(_promise)
}

export default callAsync

符合util.promisify 方法特征 \
\
1 输入的方法参数最后一个typeof === 'function' \
2 最后一个参数返回的第一个参数,总是err

注意this 指针丢失需要开发主动避免哦 \
\
可以使用 bind(this) 将指针重新找回 \
const bindCall = call.bind(that) \
await bindCall(fs.write, input) \
await bindCall(fs.open, ‘a.txt’, ‘r+’, 0o654)

参考:

await-to-js

callAsync 思想完全来源于 《await-to-js》,做了点演进。