-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ES6 系列之我们来聊聊 Async #100
Comments
消灭零评论 ^_^ |
如果 await 后面跟的不是 promise ,那么是不是,就不是所谓的顺序执行了! |
最后2个"async 会取代 Promise 吗?" 看着怪怪的 |
@mqyqingfeng 想问一下题主, 网上有说是 ES7 的,也有说是 ES8 的 :-) |
如果 await 后面的 x 不是 promise 会转换为 promise.resolve(x),也就是还是返回的 promise |
ES8 (2017) 在babel官网有 |
// 并发二
async function loadData(urls) {
// 并发读取 url
const textPromises = urls.map(async url => {
const response = await fetch(url);
return response.text();
});
// 按次序输出
for (const textPromise of textPromises) {
console.log(await textPromise);
}
} map 循环里是不是不该加 await ,才能实现并发读取 |
@heyunjiang 都是对的,都可以实现。 |
async看了有三遍了,一直忘,总是感觉很奇怪下面这段代码 async function setTime(ms) {
await setTimeout(() => {console.log('aaaaaaaaa')}, ms)
}
async function print(val, ms) {
await setTime(ms)
console.log(val)
}
print('vvvvvvvv', 3000);
// vvvvvvvv
// Promise{<resolved>: undefined}
// aaaaaaaaa 像上面的代码,为何直接await setTimeout,print函数没有等setTimeout执行完毕后再打印? 好吧,还是我自己不够理解啊。。。 async function test() {
const tt = await setTimeout(() => {console.log(333)}, 3000)
console.log(444)
console.log(tt)
}
test()
// 444
// 562
// Promise{<resolved>: undefined}
// 333 |
@lizhongzhen11 这个地方你可以想象下,await 后面直接接个异步的函数,比如你例子当中的 setTimeout 方法,那后面的程序什么时候知道你这个异步的方法被执行完了呢?promise 就不一样了,虽然也是异步执行,但是这个 promise 被 resolve 后就表明这个 promise (异步任务)执行结束了。那么就可以开始执行下面的方法了。 |
不是promise会转为promise,resolved后就继续往下执行了
|
看完后感觉理解的又深了不少~很赞 |
== 0 ==
async function test0() {
await setTimeout(() =>console.log(111), 3000)
console.log(222)
}// 222 111
// 问题提出:为啥await没有起作用?await不是返回一个promise,当promise决议后才下一步吗?
== 1 ==
async function test1() {
await new Promise(resolve => setTimeout(()=>console.log(111), 1000))
// 如果没有resolve 就不会往下执行
console.log(222)// 未执行
}// 111
== 2 ==
async function test2() {
await new Promise(resolve => setTimeout(()=>resolve(console.log(111)), 1000))
console.log(222)
}// 111 222 正常版本
== 3 ==
async function test3() {
await Promise.resolve(setTimeout(()=>console.log(111),500));
console.log(222)
}// 222 111 因为 await后面是一个已经resolve的promise 所以直接下一步
== 4 ==
async function test4() {
await Promise.all([setTimeout(()=>console.log(111),500)]);
console.log(222)
}// 222 111 当all的数组元素不是promise的时候 会调用Promise.resolve方法包装 产生与3一样结果
== 5 ==
async function test5(){
await new _Promise(resolve=>setTimeout(()=>resolve(console.log(111)),1000));
console.log(222)
}// 111 222 _Promise是自己模拟的promise 由上, async function test6() {
await setTimeout(()=>console.log(1),1000);
await setTimeout(()=>console.log(2),500);
await console.log(3)
}// 3 2 1 当 await后面跟的不是promise是普通函数的话,后面的普通函数实际上看成由Promise.resolve包裹后执行 再看下面这个例子更清晰: test7();
async function test7() {
console.log(1)
await console.log(2)
console.log(3)
}
console.log(4)
// 1 2 4 3 test7 等价于 test7_1 test7_1()
async function test7_1() {
console.log(1)
await Promise.resolve(console.log(2));
console.log(3)
}
console.log(4)
// 1 2 4 3 进而等价于 test7_2 function test7_2() {
console.log(1)
Promise.resolve(console.log(2)).then(()=>{console.log(3)})
}
test7_2(); 而产生阻塞的情况是:await后面是未被决议的promise对象才会产生阻塞 代码运行环境是:node v15.9.0; 补充阻塞情况的代码 test8();
async function test8() {
await new Promise(resolve => {
console.log(1);
setTimeout(() => {
// resolve();
}, 100);
});
// 由于上一个promise未决议,下面的代码不会执行
await new Promise(resolve => {
console.log(2);
setTimeout(() => {
resolve();
}, 100);
});
await console.log(3);
console.log(5); // 5 也不会执行哦
}
// 但并不影响函数外的执行
console.log(6);
输出:1、6 |
|
我理解的:如果不是promise,会自动转成立即resolved的promise.因为上面立即resolved了,所以直接执行下面代码了。 |
真的干货满满 |
(async () => {
const listPromise = getList();
const anotherListPromise = getAnotherList();
await listPromise;
await anotherListPromise;
})(); 这个写法有点不理解,就是 getList 和 getAnotherList。返回的是promise。如果后面有代码要执行,就要等这两个请求回来了再执行? |
原来to.js就封装了一个简单的promise函数,我们项目里面居然用的npm中的库,学习了。 |
@chenhuiYj 我觉得是的,这样的写法只是为了让两个异步函数并行执行,而不是一先一后执行,下面的await是用来获取上面异步函数的返回数据。但是程序还是要等到上面两个函数都执行完毕,才会执行await下面的其他代码的。 |
输出有问题吧,如果await后的promise已经决议,就应该是同步了啊。我开始一直没理解为啥决议了还是异步。
相当于
应该输出 1 2 4 3 |
请问下你是在哪里运行的?为什么控制台结果跟你的不一样? |
已修正,详见 #100 (comment) 感谢指正 💙 |
await-to-js 是个好东西 |
to不就是golang的错误处理吗?go自己的原生错误处理就被喷的不行,结果被js捡起来了...还成了好东西 |
async
ES2017 标准引入了 async 函数,使得异步操作变得更加方便。
在异步处理上,async 函数就是 Generator 函数的语法糖。
举个例子:
当你使用 async 时:
其实 async 函数的实现原理,就是将 Generator 函数和自动执行器,包装在一个函数里。
spawn 函数指的是自动执行器,就比如说 co。
再加上 async 函数返回一个 Promise 对象,你也可以理解为 async 函数是基于 Promise 和 Generator 的一层封装。
async 与 Promise
严谨的说,async 是一种语法,Promise 是一个内置对象,两者并不具备可比性,更何况 async 函数也返回一个 Promise 对象……
这里主要是展示一些场景,使用 async 会比使用 Promise 更优雅的处理异步流程。
1. 代码更加简洁
2. 错误处理
在这段代码中,try/catch 能捕获 fetchData() 中的一些 Promise 构造错误,但是不能捕获 JSON.parse 抛出的异常,如果要处理 JSON.parse 抛出的异常,需要添加 catch 函数重复一遍异常处理的逻辑。
在实际项目中,错误处理逻辑可能会很复杂,这会导致冗余的代码。
async/await 的出现使得 try/catch 就可以捕获同步和异步的错误。
3. 调试
因为 then 中的代码是异步执行,所以当你打断点的时候,代码不会顺序执行,尤其当你使用 step over 的时候,then 函数会直接进入下一个 then 函数。
而使用 async 的时候,则可以像调试同步代码一样调试。
async 地狱
async 地狱主要是指开发者贪图语法上的简洁而让原本可以并行执行的内容变成了顺序执行,从而影响了性能,但用地狱形容有点夸张了点……
例子一
举个例子:
getList() 和 getAnotherList() 其实并没有依赖关系,但是现在的这种写法,虽然简洁,却导致了 getAnotherList() 只能在 getList() 返回后才会执行,从而导致了多一倍的请求时间。
为了解决这个问题,我们可以改成这样:
也可以使用 Promise.all():
例子二
当然上面这个例子比较简单,我们再来扩充一下:
因为 await 的特性,整个例子有明显的先后顺序,然而 getList() 和 getAnotherList() 其实并无依赖,submit(listData) 和 submit(anotherListData) 也没有依赖关系,那么对于这种例子,我们该怎么改写呢?
基本分为三个步骤:
1. 找出依赖关系
在这里,submit(listData) 需要在 getList() 之后,submit(anotherListData) 需要在 anotherListPromise() 之后。
2. 将互相依赖的语句包裹在 async 函数中
3.并发执行 async 函数
继发与并发
问题:给定一个 URL 数组,如何实现接口的继发和并发?
async 继发实现:
async 并发实现:
async 错误捕获
尽管我们可以使用 try catch 捕获错误,但是当我们需要捕获多个错误并做不同的处理时,很快 try catch 就会导致代码杂乱,就比如:
为了简化这种错误的捕获,我们可以给 await 后的 promise 对象添加 catch 函数,为此我们需要写一个 helper:
整个错误捕获的代码可以简化为:
async 的一些讨论
async 会取代 Generator 吗?
Generator 本来是用作生成器,使用 Generator 处理异步请求只是一个比较 hack 的用法,在异步方面,async 可以取代 Generator,但是 async 和 Generator 两个语法本身是用来解决不同的问题的。
async 会取代 Promise 吗?
async 函数返回一个 Promise 对象
面对复杂的异步流程,Promise 提供的 all 和 race 会更加好用
Promise 本身是一个对象,所以可以在代码中任意传递
async 的支持率还很低,即使有 Babel,编译后也要增加 1000 行左右。
参考
ES6 系列
ES6 系列目录地址:https://github.com/mqyqingfeng/Blog
ES6 系列预计写二十篇左右,旨在加深 ES6 部分知识点的理解,重点讲解块级作用域、标签模板、箭头函数、Symbol、Set、Map 以及 Promise 的模拟实现、模块加载方案、异步处理等内容。
如果有错误或者不严谨的地方,请务必给予指正,十分感谢。如果喜欢或者有所启发,欢迎 star,对作者也是一种鼓励。
The text was updated successfully, but these errors were encountered: