Open jackieli123723 opened 7 years ago
const Router = require('koa-router')
const article = require('../services/article')
const user = require('../services/user')
let api = new Router()
api.get('/article/list', async (ctx) => {
try {
let data = await article.list()
ctx.body = {
success: true,
message: 'success',
data: data
}
} catch (err) {
ctx.body = {
success: false,
message: err,
data: []
}
}
})
module.exports = api
我们已经听说过这个功能了一段时间了,但让我们深入了解一下,看看它是如何工作的。为了能够掌握这篇文章的内容,你需要对承诺和发电机的坚定的了解。这些资源可以帮助你。
使用承诺
我们假设我们有如下代码。在这里我正在包装一个HTTP请求Promise。这个承诺body在成功的情况下实现,err否则就被拒绝。它每次从这个博客中提取HTML随机文章。
以上所示承诺代码的典型用法如下。在那里,我们构建了一个承诺链,将HTML页面转换为Mark的一个子集,然后进入终端友好的输出,最后打印使用console.log。永远记住在.catch你的承诺中添加处理程序。
当运行时,代码段生成输出,如下面的屏幕截图所示。
该代码“比使用回调更好”,当涉及到读取代码的顺序时。
使用发电机 我们已经探索发电机,作为过去以html合成“同步”方式提供的方式。即使该代码现在有些同步,但是涉及到相当多的包装,并且生成器可能不是最直接的方式来完成我们想要的结果,所以我们可能最终会坚持承诺。
请记住,您应该将yield呼叫包装在try/ catch块中,以保护我们在使用承诺时添加的错误处理。 不用说,使用这样的发电机不能很好地扩展。除了在组合中引入不直观的语法,您的迭代器代码将高度耦合到正在使用的生成器函数。这意味着您必须经常更改它,因为您将新的await表达式添加到生成器中。一个更好的选择是使用即将到来的异步功能。
使用async/await 当Async函数终于走上了路,我们将能够采取我们Promise的实现,并利用同步的生成器风格。这种方法的另一个好处是,getRandomPonyFooArticle只要返回一个承诺,就可以等待,您完全不必改变。
请注意,await只能在标有async关键字的功能中使用。它与发电机类似,在您的上下文中暂停执行,直到承诺落定。如果期待已久的表达不是一个承诺,它就是承诺。
同样, - ,只是像发电机-记住,你应该换await在try/ catch让你可以捕捉并从内处理在等待承诺的错误async功能。 此外,Async函数总是返回一个Promise。在未捕获的异常的情况下,该承诺被拒绝,否则解决了该async函数的返回值。这使我们能够调用一个async功能,并将其与常规的基于promise的延续相结合。以下示例显示了两者可能如何组合(请参阅Babel REPL)。
回到前面的例子,这意味着我们可以return txt从我们的async read功能,并允许消费者继续使用承诺或另一个异步功能。这样,您的read功能就只关注从Pony Foo的随机文章中提取终端可读的Markdown。
叉在路上
在异步代码流中,通常同时执行两个或多个任务。虽然Async功能使得编写异步代码更容易,但它们也适用于串行的代码。也就是说:一次执行一个操作的代码。一个具有多个await表达式的函数将在每个await表达式上一次暂停,直到它Promise被解决,然后再重新执行并移动到下一个await表达式- 与我们使用生成器和我们观察到的情况不同yield。
要解决这个问题,您可以使用它Promise.all来创建一个可以await启用的单一承诺。当然,最大的问题是习惯使用Promise.all而不是将所有内容都运行在一个系列中,否则会使代码的性能下降。
以下示例显示了如何await可以同时解决三个不同的承诺。鉴于await暂停您的async函数并且await Promise.all表达式最终解析成results数组,我们可以使用解构来从该数组中拉出单个结果。
在某些时候,有一个await*替代上面的代码,在那里你不必包裹你的承诺Promise.all。巴别5仍然支持它,但它是从规格(和从巴别6)掉下来- 因为原因。
你仍然可以做一些all = Promise.all.bind(Promise)比较简单的替代方法Promise.all。这样做的一个好处就是你可以做同样的事情Promise.race,而没有一个等同的await*。
错误处理 请注意,错误在一个async函数内“静默地”被吞噬- 就像正常的Promises一样。除非我们在表达式附近添加try/ catch阻止await,async否则无法捕获异常 - 无论是在函数体中被提出还是在暂停期间被抛出await- 将拒绝该async函数返回的承诺。
自然,这可以被看作是一种力量:你可以利用try/ catch惯例,你无法用回调来处理这些事情,而且有些能够与Promises进行交互。在这个意义上,Async功能类似于生成器,您也可以利用try/ catch感谢函数执行停止将异步流转换为同步代码。
此外,您可以从async函数外部捕获这些异常,只需.catch在其返回的承诺中添加一个子句即可。虽然这是将try/ catch错误处理风格与Promises中的.catch子句相结合的灵活方式,但它也可能导致混淆,并最终导致错误进入未处理。
我们需要小心和教育我们自己的不同方式,我们可以注意到异常,然后处理,记录或阻止它们。
使用async/ await今天 在今天的代码中使用Async函数的一种方法是通过Babel。这涉及到一系列模块,但是如果您愿意,您可以随时提出一个将所有这些模块包装在一个模块中的模块。我将其npm-run作为一种有用的方式来保存在本地安装的软件包中。
下面的命令将编译example.js通过browserify同时使用babelify,使支持异步功能。然后,您可以将脚本管道node或将其保存到磁盘。
进一步阅读 Async功能的规范草案令人惊讶的很短,如果您热衷于了解有关此即将到来的功能的更多信息,应该补充一个有趣的阅读。
我已经粘贴了一段代码,旨在帮助您了解async函数内部的工作原理。尽管我们不能填充工具新的关键字,它在理解发生的事情的幕后方面有帮助async/ await。
也就是说,了解Async函数内部利用发电机和承诺应该是有用的。 首先,接下来,下面的一点显示一个async function声明如何被放入一个常规的function返回spawn使用生成函数进给的结果- 我们将会考虑await作为句法等价物yield。
在spawn一个承诺中,围绕着将逐步通过用户代码(由用户代码组成的)生成器函数的代码,将值转发到“生成器”代码(async函数体)中。在这个意义上,我们可以看到,异步函数真的是语法糖在发生器和承诺之上,这使得您了解每个这些事情是如何工作的,以便更好地了解如何混合,匹配和将这些不同类型的异步代码流合并在一起。
突出显示的代码段应该有助于您了解async/ awaitalgorithm 如何迭代生成器序列(await表达式),将序列中的每个项目包裹在一个承诺中,然后用序列中的下一个步骤进行链接。当序列结束或其中一个承诺被拒绝时,底层生成函数返回的承诺得到解决。