115

重构:从Promise到Async/Await | Fundebug博客

 7 years ago
source link: https://blog.fundebug.com/2017/12/13/reconstruct-from-promise-to-async-await/?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

重构:从Promise到Async/Await

摘要: 夸张点说,技术的发展与历史一样,顺之者昌,逆之者亡。JS开发者们,赶紧拥抱Async/Await吧!

早在半年多之前,我就在鼓吹Async/Await替代Promise的6个理由,似乎还招致了一些批评。然而,直到最近,我才真正开始进行代码重构,抛弃Promise,全面使用Async/Await。因为,Node 8终于LTS了

Async/Await真的比Promise好吗?

是的是的。

这些天,我大概重构了1000行代码,最大的感觉是代码简洁了很多:

  • 真正地用同步的方式写异步代码
  • 不用写then及其回调函数,减少代码行数,也避免了代码嵌套
  • 所有异步调用可以写在同一个代码块中,无需定义多余的中间变量
  • async函数会隐式地返回一个Promise,因此可以直接return变量,无需使用Promise.resolve进行转换

下面,我们可以通过一个非常简单的示例来体验一下Async/Await的酸爽:

const Promise = require("bluebird")
var readFile = Promise.promisify(require("fs").readFile)

// 使用Promise
function usePromise()
{
let a
readFile("a.txt", "utf8")
.then(tmp =>
{
a = tmp
return readFile("b.txt", "utf8")
})
.then(b =>
{
let result = a + b
console.log(result) // 输出"Hello, Fundebug!"
})

}

// 使用Async/Await
async function useAsyncAwait()
{
let a = await readFile("a.txt", "utf8")
let b = await readFile("b.txt", "utf8")
let result = a + b
console.log(result) // 输出"Hello, Fundebug!"
}

usePromise()
useAsyncAwait()

由示例可知,使用Async/Await极大地简化了代码,使得代码可读性提高了非常多。

Async/Await真的替代了Promise?

是的是的。

对于Async/Await替代Promise的6个理由,批评者执着于Async/Await是基于Promise实现的,因此替代这个词不准确,这就有点尴尬了。

一方面,这里替代的是异步代码的编写方式,并非完全抛弃大家心爱的Promise,地球人都知道Async/Await是基于Promise的,不用太伤心;另一方面,Promise是基于回调函数实现的,那Promise也没有替代回调函数咯?

重构代码之后,我仍然用到了Promise库bluebird。”Talk is cheap, Show me the code!”,大家不妨看看两个示例。

示例2:Promise.promisify

使用Promise.promisify将不支持Promise的方法Promise化,调用异步接口的时候有两种方式:

const Promise = require("bluebird")
var readFile = Promise.promisify(require("fs").readFile)

// 使用Promise
function usePromise()
{
readFile("b.txt", "utf8")
.then(b =>
{
console.log(b)
})
}

// 使用Async/Await
async function useAsyncAwait()
{
var b = await readFile("b.txt", "utf8")
console.log(b) // 输出"Fundebug!"
}

usePromise()
useAsyncAwait()

Fundebug是全栈JavaScript错误监控平台,支持各种前端和后端框架,可以帮助您第一时间发现BUG!

示例3:Promise.map

使用Promise.map读取多个文件的数据,调用异步接口的时候有两种方式:

const Promise = require("bluebird")
var readFile = Promise.promisify(require("fs").readFile)
var files = ["a.txt", "b.txt"]

// 使用Promise
function usePromise()
{
Promise.map(files, file =>
{
return readFile(file, "utf8")
})
.then(results =>
{
console.log(results)
})
}

// 使用Async/Await
async function useAsyncAwait()
{
var results = await Promise.map(files, file =>
{
return readFile(file, "utf8")
})
console.log(results)
}

usePromise()
useAsyncAwait()

没错,我的确使用了Promise库,readFile与Promise.map都是Promise函数。但是,在调用readFile与Promise.map函数时,使用Async/Await与使用Promise是两种不同写法,它们是相互替代的关系。

Async/Await有什么问题吗?

有啊有啊。

使用了await的函数定义时要加一个async,调用异步函数的时候需要加一个await,这玩意写多了也觉着烦,有时候还容易忘掉。不写async代码直接报错,不写await代码执行会出错。

const Promise = require("bluebird")
var readFile = Promise.promisify(require("fs").readFile)

// 没有Async
function withoutAsync()
{
let b = await readFile("b.txt", "utf8") // 报错"SyntaxError: Unexpected identifier"
console.log(b)
}

// 没有await
async function withoutAwait()
{
let b = readFile("b.txt", "utf8")
console.log(b) // 打印"Promise..."
}

withoutAsync()
withoutAwait()

既然Async/Await写着有点添乱,可不可以不写呢?我想以后应该是可以的,只要能够自动识别异步代码就行了,这应该也是未来的发展方向。至于说如何实现,那我就不知道了哎。

JavaScript的异步编写方式,从回调函数到Promise再到Async/Await,表面上只是写法的变化,本质上则是语言层的一次次抽象,让我们可以用更简单的方式实现同样的功能,而程序员不需要去考虑代码是如何执行的。在我看来,这样的进步应该不会停止,有一天我们也许不用写Async/Await了!

关于Fundebug

Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了70亿+错误事件,付费客户有阳光保险、达令家、核桃编程、荔枝FM、微脉等众多品牌企业。欢迎大家免费试用

您的用户遇到BUG了吗?

体验Demo 免费使用

Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK