ES2017异步函数现已正式可用
本文参考文章:https://css-tricks.com/using-es2017-async-functions/
转载请注明出自:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。
ES2017标准已于2017年6月份正式定稿了,并广泛支持最新的特性:异步函数。如果你曾经被异步 JavaScript 的逻辑困扰,这么新函数正是为你设计的。
异步函数或多或少会让你编写一些顺序的 JavaScript 代码,但是却不需要在 callbacks、generators 或 promise 中包含你的逻辑。
如下代码:
function logger() {
let data = fetch('http://sampleapi.com/posts')
console.log(data)
}
logger()
这段代码并未实现你的预期。如果你是在JS中编写的,那么你可能会知道为什么。
下面这段代码,却实现了你的预期。
async function logger() {
let data = await fetch('http:sampleapi.com/posts')
console.log(data)
}
logger()
这段代码起作用了,从直观上看,仅仅只是多了 async 和 await 两个词。
ES6 标准之前的 JavaScript 异步函数
在深入学习 async 和 await 之前,我们需要先理解 Promise。为了领会 Promise,我们需要回到普通回调函数中进一步学习。
Promise 是在 ES6 中引入的,并促使在编写 JavaScript 的异步代码方面,实现了巨大的提升。从此编写回调函数不再那么痛苦。
回调是一个函数,可以将结果传递给函数并在该函数内进行调用,以便作为事件的响应。同时,这也是JS的基础。
function readFile('file.txt', (data) => {
// This is inside the callback function
console.log(data)
}
这个函数只是简单的向文件中记录数据,在文件完成之前进行读取是不可能的。这个过程似乎很简单,但是如果想要按顺序读取并记录五个不同的文件,需要怎么实现呢?
没有 Promise 的时候,为了按顺序执行任务,就需要通过嵌套回调来实现,就像下面的代码:
// This is officially callback hell
function combineFiles(file1, file2, file3, printFileCallBack) {
let newFileText = ''
readFile(string1, (text) => {
newFileText += text
readFile(string2, (text) => {
newFileText += text
readFile(string3, (text) => {
newFileText += text
printFileCallBack(newFileText)
}
}
}
}
这就很难推断函数下面会发生什么,同时也很难处理各种场景下发生的错误,比如其中某个文件不存在的情况。
Promise 改善了这种情况
这正是 Promise 的优势所在,Promise 是对还未产生的数据的一种推理。Kyle Simpson 将 Promise 解释为:就像在快餐店里点餐一样。
- 点餐
- 为所点的午餐付费,并拿到排队单号
- 等待午餐
- 当你的午餐准备好了,会叫你的单号提醒你取餐
- 收到午餐
正如上面的这种场景,当你等餐时,你是无法吃到午餐的,但是你可以提前为吃午餐做好准备。你可以进行其它事情,此时你知道午餐就要来了,虽然此刻你还无法享用它,但是这个午餐已经“promise”给你了。这就是所谓的 promise,表示一个最终会存在的数据的对象。
readFile(file1)
.then((file1-data) => { /* do something */ })
.then((previous-promise-data) => { /* do the next thing */ })
.catch( /* handle errors */ )
上面是 Promise 语法。它主要的优点就是可以将队列事件以一种直观的方式链接在一起。虽然这个示例清晰易懂,但是还是用到了回调。Promise 只是让回调显得比较简单和更加直观。
最佳方式:async / await
若干年前,async 函数纳入了 JavaScript 生态系统。就在上个月,async 函数成为了 JavaScript 语言的官方特性,并得到了广泛支持。
async 和 await 是建立在 Promise 和 generator上。本质上,允许我们使用 await 这个关键词在任何函数中的任何我们想要的地方进行暂停。
async function logger() {
// pause until fetch returns
let data = await fetch('http://sampleapi.com/posts')
console.log(data)
}
上面这段代码运行之后,得到了想要的结果。代码从 API 调用中记录了数据。
这种方式的好处就是非常直观。编写代码的方式就是大脑思考的方式,告诉脚本在需要的地方暂停。
另一个好处是,当我们不能使用 promise 时,还可以使用 try 和 catch:
async function logger () {
try {
let user_id = await fetch('/api/users/username')
let posts = await fetch('/api/`${user_id}`')
let object = JSON.parse(user.posts.toString())
console.log(posts)
} catch (error) {
console.error('Error:', error)
}
}
上面是一个刻意写错的示例,为了证明了一点:在运行过程中,catch 可以捕获任何步骤中发生的错误。至少有三个地方,try 可能会失败,这是在异步代码中的一种最干净的方式来处理错误。
我们还可以使用带有循环和条件的 async 函数:
async function count() {
let counter = 1
for (let i = 0; i < 100; i++) {
counter += 1
console.log(counter)
await sleep(1000)
}
}
这是一个很简答的例子,如果运行这段程序,将会看到代码在 sleep 调用时暂停,下一个循环迭代将会在1秒后启动。
要点和细节
相信我们已经感受到了 asyns 和 await 的美妙之处,接下来让我们深入了解一下细节:
- async 和 await 建立在 Promise 之上。使用 async,总是会返回一个 Promise。请记住这一点,因为这也是容易犯错的地方。
- 当执行到 await 时,程序会暂停当前函数,而不是所有代码
- async 和 await 是非阻塞的
- 依旧可以使用 Promise helpers,例如 Promise.all( )
正如之前的示例:
async function logPosts () {
try {
let user_id = await fetch('/api/users/username')
let post_ids = await fetch('/api/posts/<code>${user_id}')
let promises = post_ids.map(post_id => {
return fetch('/api/posts/${post_id}')
}
let posts = await Promise.all(promises)
console.log(posts)
} catch (error) {
console.error('Error:', error)
}
}
- await 只能用于声明为 async 的函数中
- 因此,不能在全局范围内使用 await
如下代码:
// throws an error
function logger (callBack) {
console.log(await callBack)
} // works!
async function logger () {
console.log(await callBack)
}
现已正式可用
到2017年6月,几乎所有浏览器都可以使用 async 和 await。为了确保你的代码随时可用,则需要使用 Babel 将你的 JavaScript 代码编译为旧浏览器也支持的语法。
如果对更多ES2017内容感兴趣,请访问ES2017特性的完整列表。
相关阅读:
ES2017异步函数现已正式可用的更多相关文章
- 更优雅的方式: JavaScript 中顺序执行异步函数
火于异步 1995年,当时最流行的浏览器--网景中开始运行 JavaScript (最初称为 LiveScript). 1996年,微软发布了 JScript 兼容 JavaScript.随着网景.微 ...
- 『审慎』.Net4.6 Task 异步函数 比 同步函数 慢5倍 踩坑经历
异步Task简单介绍 本标题有点 哗众取宠,各位都别介意(不排除个人技术能力问题) —— 接下来:我将会用一个小Demo 把 本文思想阐述清楚. .Net 4.0 就有了 Task 函数 —— 异步编 ...
- 14.并发与异步 - 3.C#5.0的异步函数 -《果壳中的c#》
14.5.2 编写异步函数 private static readonly Stopwatch Watch = new Stopwatch(); static void Main(string[] a ...
- Net4.6 Task 异步函数 比 同步函数 慢5倍 踩坑经历
Net4.6 Task 异步函数 比 同步函数 慢5倍 踩坑经历 https://www.cnblogs.com/shuxiaolong/p/DotNet_Task_BUG.html 异步Task简单 ...
- 新技能GET!在前端表格中花式使用异步函数的奥义
背景 60年代时,操作系统中独立运行的单元通常是进程.但随着计算机技术的发展,人们发现在进程运行过程中,创建.撤销与切换都要花费较大的时空开销. 到了80年代为了解决这一问题,出现了更小的独立运行基本 ...
- 异步控制---实现函数asyncAll,在执行完传入数组中func1,func2,func3异步函数后,输出“end”
实现函数asyncAll,在执行完传入数组中func1,func2,func3异步函数后,输出"end" function func1(callback) { setTimeout ...
- Node.js用ES6原生Promise对异步函数进行封装
Promise的概念 Promise 对象用于异步(asynchronous)计算..一个Promise对象代表着一个还未完成,但预期将来会完成的操作. Promise的几种状态: pending:初 ...
- 异步函数封装请确保异步性(Javascript需要养成的良好习惯)
背景假设: 你有许多的配置信息存放在服务器上,因为配置太多,不希望每次都把所有的配置信息都写到前端,希望能需要用的时候再获取就好了. 因为Javascript单线程运行,你不希望堵塞ui渲染于是你专门 ...
- GCD,用同步/异步函数,创建并发/串行队列
队列 第一个参数:C语言字符串,标签 第二个参数: DISPATCH_QUEUE_CONCURRENT:并发队列 DISPATCH_QUEUE_SERIAL:串行队列 dispatch_queue_ ...
随机推荐
- python新手之一环境安装
今天开始学习python,首先环境安装 1.在https://www.python.org/downloads/下载python2.X或者3.X(ps:这里建议下载32位的python ,因为64位p ...
- Maven入门2-pom.xml文件与settings.xml文件
Maven入门2-pom.xml文件与settings.xml文件 本文内容来源于官网文档部分章节,settings.xml文件:参考http://maven.apache.org/settings. ...
- 剥析surging的架构思想
1.前言 前面第一篇阐述了采用基于.NET CORE微服务架构,应用surging服务端与客户端之间进行通信的简单示例以及对于surging服务化框架简单介绍.在这篇文章中,我们将剥析surgin ...
- 一个简单的时间轴demo
一个时间轴的组成 使用一个块级元素包裹内容,并未块级元素设置边框 定义圆形或者菱形等元素标签,子元素设置偏移或者定位元素将图标定位到边框上 使其中的内容不溢出,自动换行,内容自动撑高 英文自动换行:w ...
- Hadoop的介绍、搭建、环境
HADOOP背景介绍 1.1Hadoop产生背景 HADOOP最早起源于Nutch.Nutch的设计目标是构建一个大型的全网搜索引擎,包括网页抓取.索引.查询等功能,但随着抓取网页数量的增加,遇到了严 ...
- The request sent by the client was syntactically incorrect问题解决
The request sent by the client was syntactically incorrect意思嘛,google翻译一下 通过日志不难看出,是由参数不匹配造成的. 所以对于Da ...
- 对JavaScript闭包的理解
闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 在开始了解闭包前我们必须要先理解JavaScript的变量作用域. 一.变量的作用域无非就是两 ...
- (转)通过Net-Speeder为搬瓦工提升网速
为了解决丢包问题,最简单粗暴的方法就是双倍发送,即同一份数据包发送两份.这样的话在服务器带宽充足情况下,丢包率会平方级降低.直接优点是降低丢包率,直接缺点是耗费双倍流量.一些延伸影响是更容易触发快速恢 ...
- C语言基础 - 输出1-100万之间的素数
其实这个很简单 代码 网上也一大堆... //判断素数 BOOL isPrime(int num) { for (int i = 2; i <= sqrt(num); i++) { //能整除则 ...
- css阴影,边框,渐变,背景
一.box-shadow: 参数1,参数2 阴影位置偏移量 参数3 模糊半径 参数4 扩展半径 负数 0 默认值 正数 参数5 阴影的颜色 参数6 设置内阴影 inset 默认是外阴影 多个阴影使用, ...