欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

Callback到Promise再到Async进化初探

发布时间:2025/6/15 编程问答 43 豆豆
生活随笔 收集整理的这篇文章主要介绍了 Callback到Promise再到Async进化初探 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

题外:今天尝试了一下从Markdown文件经过ejs再到html文件的整个过程,这也是Hexo这种静态博客生成过程中的一环。这过程中,用到的Node中的fs系统,写的过程中恰好也经历了从Callback到Promise再到Async的转变。文末有福利哦!

在Node开发过程中,经常会遇到异步的情况,异步简单的说就是一个函数在返回时,调用者不能得到最终结果,而是需要等待一段时间才能得到,那么这个函数可以算作异步函数。那在Node开发中具体可以体现为资源的请求,例如访问数据库、读写文件等等。下面举个小例子来代码演示一下。

Callback

先上代码:

const fs = require('fs'),ejs = require('ejs'),matter = require('gray-matter'),showdown = require('showdown'),converter = new showdown.Converter()fs.readFile('./source/hello.md', 'utf8', (error, data) => {if (error) {console.log(error)return} else {const mdData = matter(data)const html = converter.makeHtml(mdData.content)fs.readFile('./views/index.ejs', 'utf8', (error, data) => {if (error) {console.log(error)return} else {// ejs to htmlconst template = ejs.compile(data)const htmlStr = template({content: html})fs.writeFile('./public/index.html', htmlStr, (error) => {if (error) {console.log(error)return} else {console.log('success')}})}})} })

可以看到,这只是写了三个读写文件,嵌套就显得非常臃肿,可以预见到当有更多的callback将是怎样一个情景,代码做了什么东西就不解释了,主要看一下callback的场景,在读或写文件之后可以跟一个回调函数,当前一个读文件操作完成之后,才能在回调中利用结果来执行下一个读文件和写文件,通过回调来保证函数的执行顺序。具体fs的使用,可见Node-fs文档

Promise

来看看引入Promise之后的写法:

const readFileAsync = function (path) {return new Promise((resolve, reject) => {fs.readFile(path, 'utf8', (error, data) => {if (error) {reject(error)} else {resolve(data)}})}) } const writeFileAsync = function (path, data) {return new Promise((resolve, reject) => {fs.writeFile(path, data, (error, data) => {if (error) {reject(error)} else {resolve(data)}})}) }let html = '' readFileAsync('./source/hello.md').then((data1) => {const mdData = matter(data1)html = converter.makeHtml(mdData.content)return readFileAsync('./views/index.ejs')}).then((data2) => {const template = ejs.compile(data2)const htmlStr = template({content: html})return writeFileAsync('./public/index2.html', htmlStr)}).then(() => console.log('success')).catch(error => console.log(error))

这里只是简单的用Promise封装了一下fs的两个函数,拿其中一个函数来说,readFileAsync返回了一个Promise对象,这样就可以通过这个对象来使用then进行结果回调,虽然在封装的时候需要写一些代码,但是当有多处使用的时候,代码可以明显的简洁许多,不同再一层一层地向右缩进。另外有一些工具库如bluebird提供了API,可以很方便地处理异步。

在下面的代码中使用bluebird

Async await

还是先上代码:

const fs = require('fs'),ejs = require('ejs'),matter = require('gray-matter'),showdown = require('showdown'),converter = new showdown.Converter(),Promise = require('bluebird')Promise.promisifyAll(fs)async function renderHtml() {const data1 = await fs.readFileAsync('./source/hello.md', 'utf8')const mdData = matter(data1)const html = converter.makeHtml(mdData.content)const data2 = await fs.readFileAsync('./views/index.ejs', 'utf8')const template = ejs.compile(data2)const htmlStr = template({content: html})fs.writeFile('./public/index4.html', htmlStr)console.log('success') }renderHtml()

在Node7.6以上就已经支持async function了,定义时只需要在function之前添加async关键字,而await也只能在async function中使用,一般会跟一个Promise对象,表示等待Promise返回结果后,再继续执行。

可以看到上面的函数已经非常顺序化了,当有n个异步函数回调时,只需要顺序写就可以啦。可以看出,其实async await也离不开Promise,只不过写法上消除了then中带有callback的那一丝丝影子,让代码更加优雅~,因为没有了then,可以用try catch进行错误处理

VSCode插件推荐

小彩蛋来啦,正好结合这个例子,为方便实时看到每一步的执行结果,推荐一个VSCode
插件:Quokka.ja

可以实时地进行代码的执行结果,再也不用console.log之后去看终端了。当然,在实际开发中可能应用性不是特别强,尤其是对于上下文强依赖型、后端请求依赖型的场景。

总结

以上是生活随笔为你收集整理的Callback到Promise再到Async进化初探的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。