飞雪连天射白鹿,笑书神侠倚碧鸳

0%

通过await在definePorperty中的表现重新认识async

defineProperty中无法获取await get()的值
再来看看async/await

群里聊天时看到抛出的一个问题和相关代码,Object.defineProperty中的get使用await为啥不能同步获取到值
用这俩语法糖执行同步任务也有一段时间了,看到这个问题还是有点懵,经过实践解决了这个问题
那通过MDN重新再了解一下async/await


异步转同步的发展过程

  • ajax需要在callback中获取结果,当有请求结果和请求参数有相互依赖时需要多层嵌套,出现回调地狱的代码问题
  • 而Promise可以在then()中拿到结果,让每步调用写法更清晰,解决回调地狱
  • async更简洁,更优雅的错误处理,易于调试

async定义一个返回Promise对象的异步函数
await会暂停异步函数的执行,并等待Promise执行,然后继续执行异步函数,并返回结果
是generator生成器的语法糖

通过俩例子了解一下async/await

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function getData(val) {
let result = new Promise(res => {
setTimeout(() => {
console.log('异步结果', val)
res(val)
}, 500)
})
console.log('异步getData', result)
return result;
}
async function getVal(val) {
let result = await getData(val)
console.log('正常的异步转同步', result)
return result;
}
console.log('getVal', getVal(1))

会发现打印的是一个Promise对象 pending状态,这也符合async的返回,而内部的函数是正常同步执行的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
async function getData2(val) {
let result = await new Promise(res => {
setTimeout(() => {
console.log('异步2结果', val)
res(val)
}, 500)
})
console.log('异步2getData2', result)
return result;
}
async function getVal2(val) {
let result = await getData2(val)
console.log('依旧正常的异步转同步', result)
}
getVal2(33)
console.log('这行还是会先于getVal2执行的哦')

原来,async/await 保证的是,同一个作用域中存在同步代码和异步代码时,等待获取到promise结果后再执行后续代码

如何解决get中的await取值

定义一个函数,改变对象的属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function def(target, key, val) {
Object.defineProperty(target, key, {
async get() {
// console.log('执行get', val)
let res = await new Promise(res => {
setTimeout(() => {
res('success')
}, 2000)
})
// console.log('结束执行Promise', res, val)
return val;
},
set(newVal) {
console.log('设置新的值', newVal)
val = newVal
}
})
}
// 为什么get()中使用async不会生效呢
var a = { id: 1 }
def(a, 'id', 1);
a.id = 2;
console.log('a.id---', a.id) // 可以看到返回的是 Promise { <pending> }

通过上文关于async/await的语法含义,解决这个问题就很简单了
目的是获取get中的await返回val而不是promise
通过代理包装一层async/await,就能正常获取get()的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 获取指定对象的当前值
async function myProxy(val) {
return await val;
}
// 对指定对象执行加法运算
async function myProxyAddition(obj, key, num) {
let result = await myProxy(obj[key])
let new_result = result + num;
obj[key] = new_result;
return new_result;
}
// 对指定对象执行加法运算
async function myProxySubtraction(obj, key, num) {
let result = await myProxy(obj[key])
let new_result = result - num;
obj[key] = new_result;
return new_result;
}
myProxyAddition(a, 'id', 3);
// myProxySubtraction(a, 'id', 3);

// 计时器的结果,每隔1秒返回
var timer = setInterval(async () => {
let result = await myProxy(a.id)
if (result >= 5) {
clearInterval(timer)
return;
}
myProxyAddition(a, 'id', 1);
}, 1000)

// 循环的结果,2秒后一起返回
[1, 1, 1, 1, 1].map(async () => {
myProxyAddition(a, 'id', 1);
})

虽然实际开发中不会遇到defineProperty中await get()的情况,但是通过这次的例子可以加深对语法糖的理解~

听说,打赏我的人最后都找到了真爱
↘ 此处应有打赏 ↙
// 用户脚本