We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
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
async是Generator的语法糖。与Generator比较,在语法上,async仅仅是把 * 换成 async;yield 换成了 await 而已。
模拟一个异步例子:
// Generator写法 function f(time) { return new Promise( (resolve, reject) => { setTimeout(() => { console.log("after time:", time) resolve() }, time) } ) } function* gen() { yield f(1000) yield f(2000) } var g = gen()
如果要获取结果,需要手动执行Genrator函数:
g.next().value.then(()=>{console.log('successs')}) g.next().value.then(()=>{console.log('successs')})
用 async 改写:
async function asyncGen() { await f(1000).then(()=>{console.log('success')}) await f(2000).then(()=>{console.log('success')}) }
如果要获取结果,直接执行asyncGen函数:
asyncGen()
可以发现 async 函数与 Geneartor 函数的区别:
async函数返回的 Promise 对象,必须等到内部所有await命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到return语句或者抛出错误。也就是说,只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。
async与Promise都是ES6对异步操作的方案,那async对于一些场景有什么优劣势?
/** * 处理单个异步操作 */ function fetch() { return ( fetchData() .then(() => { return "done" }); ) } async function fetch() { await fetchData() return "done" }; /** * 对单个异步操作返回值进行操作 */ function fetch() { return fetchData() .then(data => { if (data.moreData) { return fetchAnotherData(data) .then(moreData => { return moreData }) } else { return data } }); } async function fetch() { const data = await fetchData() if (data.moreData) { const moreData = await fetchAnotherData(data); return moreData } else { return data } }; /** * 对于流操作,一系列异步操作有着关联,一个异步操作需要使用到上一个异步操作的结果 */ function fetch() { return ( fetchData() .then(value1 => { return fetchMoreData(value1) }) .then(value2 => { return fetchMoreData2(value2) }) ) } async function fetch() { const value1 = await fetchData() const value2 = await fetchMoreData(value1) return fetchMoreData2(value2) };
function fetch() { try { fetchData() .then(result => { const data = JSON.parse(result) }) .catch((err) => { console.log(err) }) } catch (err) { console.log(err) } }
这段代码中,Promise异步操作可以使用try cathch捕获fetchData()一些promise构造的错误,不能捕获JSON.parse中的错误,如果要捕获这个错误,需要添加catch函数重复一些异常处理的逻辑。
在实际项目中,错误处理逻辑可能会很复杂,这会导致冗余的代码。
async function fetch() { try { const data = JSON.parse(await fetchData()) } catch(err) { console.log(err) } }
async/await 的出现使得 try/catch 就可以捕获同步和异步的错误。
async 地狱指开发者贪图语法上的简洁,让原本可以并行执行的操作,变成顺序执行,从而影响了性能。
例子一:
(async () => { const getList = await getList(); const getAnotherList = await getAnotherList(); })();
getList 和 getAnotherList 逻辑上没有依赖关系,但是这种写法,虽然简洁,却导致getAnotherList() 必须在 getList() 执行完之后执行,浪费了一倍的时间。
改进:
(async () => { const listPromise = getList() const anotherListPromise = getAnotherList() await listPromise await anotherListPromise })()
也可以使用Promise.all()
(async () => { Promise.all([getList(), getAnoterList()]).then() })()
例子二: 如果函数中既有依赖关系,又有并发的关系,该怎么处理呢?
(async () => { const listPromise = await getList(); const anotherListPromise = await getAnotherList(); // do something await submit(listData); await submit(anotherListData); })();
基本步骤:
async function handleList() { const listPromise = await getList(); // ... await submit(listData); } async function handleAnotherList() { const anotherListPromise = await getAnotherList() // ... await submit(anotherListData) }
async function handleList() { const listPromise = await getList(); // ... await submit(listData); } async function handleAnotherList() { const anotherListPromise = await getAnotherList() // ... await submit(anotherListData) } // 方法一 (async () => { const handleListPromise = handleList() const handleAnotherListPromise = handleAnotherList() await handleListPromise await handleAnotherListPromise })() // 方法二 (async () => { Promise.all([handleList(), handleAnotherList()]).then() })()
问题:给定一个url数组,如何实现接口的继发和并发?
async继发实现:
// 继发一 async function loadData() { const res1 = await fetch(url1) const res2 = await fetch(url2) const res3 = await fetch(url3) return 'done' } // 继发二 async function loadData(urls) { for (const url of urls) { const response = await fetch(url); console.log(await response.text()); } }
async并发实现:
// 并发一 async function loadData() { var res = await Promise.all([fetch(url1), fetch(url2), fetch(url3)]); return "whew all done"; } // 并发二 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); } }
尽管我们可以使用 try catch 捕获错误,但是当我们需要捕获多个错误并做不同的处理时,很快 try catch 就会导致代码杂乱,就比如:
async function asyncTask(cb) { try { const user = await UserModel.findById(1); if(!user) return cb('No user found'); } catch(e) { return cb('Unexpected error occurred'); } try { const savedTask = await TaskModel({userId: user.id, name: 'Demo Task'}); } catch(e) { return cb('Error occurred while saving task'); } if(user.notificationsEnabled) { try { await NotificationService.sendNotification(user.id, 'Task Created'); } catch(e) { return cb('Error while sending notification'); } } if(savedTask.assignedUser.id !== user.id) { try { await NotificationService.sendNotification(savedTask.assignedUser.id, 'Task was created for you'); } catch(e) { return cb('Error while sending notification'); } } cb(null, savedTask); }
为了简化这种错误的捕获,我们可以给 await 后的 promise 对象添加 catch 函数,为此我们需要写一个 helper:
// to.js export default function to(promise) { return promise.then(data => { return [null, data]; }) .catch(err => [err]); }
整个错误捕获的代码可以简化为:
import to from './to.js'; async function asyncTask() { let err, user, savedTask; [err, user] = await to(UserModel.findById(1)); if(!user) throw new CustomerError('No user found'); [err, savedTask] = await to(TaskModel({userId: user.id, name: 'Demo Task'})); if(err) throw new CustomError('Error occurred while saving task'); if(user.notificationsEnabled) { const [err] = await to(NotificationService.sendNotification(user.id, 'Task Created')); if (err) console.error('Just log the error and continue flow'); } }
Generator 本来是用作生成器,使用 Generator 处理异步请求只是一个比较 hack 的用法,在异步方面,async 可以取代 Generator,但是 async 和 Generator 两个语法本身是用来解决不同的问题的。
async 函数返回一个 Promise 对象
面对复杂的异步流程,Promise 提供的 all 和 race 会更加好用
Promise 本身是一个对象,所以可以在代码中任意传递
async 的支持率还很低,即使有 Babel,编译后也要增加 1000 行左右。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
ES6之async函数
async是什么
async是Generator的语法糖。与Generator比较,在语法上,async仅仅是把 * 换成 async;yield 换成了 await 而已。
模拟一个异步例子:
如果要获取结果,需要手动执行Genrator函数:
用 async 改写:
如果要获取结果,直接执行asyncGen函数:
可以发现 async 函数与 Geneartor 函数的区别:
async与Promise
async与Promise都是ES6对异步操作的方案,那async对于一些场景有什么优劣势?
代码更简洁
错误处理
这段代码中,Promise异步操作可以使用try cathch捕获fetchData()一些promise构造的错误,不能捕获JSON.parse中的错误,如果要捕获这个错误,需要添加catch函数重复一些异常处理的逻辑。
在实际项目中,错误处理逻辑可能会很复杂,这会导致冗余的代码。
async/await 的出现使得 try/catch 就可以捕获同步和异步的错误。
async 地狱
async 地狱指开发者贪图语法上的简洁,让原本可以并行执行的操作,变成顺序执行,从而影响了性能。
例子一:
getList 和 getAnotherList 逻辑上没有依赖关系,但是这种写法,虽然简洁,却导致getAnotherList() 必须在 getList() 执行完之后执行,浪费了一倍的时间。
改进:
也可以使用Promise.all()
例子二:
如果函数中既有依赖关系,又有并发的关系,该怎么处理呢?
基本步骤:
继发与并发
问题:给定一个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 行左右。
The text was updated successfully, but these errors were encountered: