题外:今天尝试了一下从Markdown
文件通过ejs
再到html
文件的整个过程,这也是Hexo
这种静态博客生成过程当中的一环。这过程当中,用到的Node
中的fs
系统,写的过程当中刚好也经历了从Callback
到Promise
再到Async
的转变。文末有福利哦!javascript
在Node
开发过程当中,常常会遇到异步的状况,异步简单的说就是一个函数在返回时,调用者不能获得最终结果,而是须要等待一段时间才能获得,那么这个函数能够算做异步函数。那在Node开发中具体能够体现为资源的请求,例如访问数据库、读写文件等等。下面举个小例子来代码演示一下。html
先上代码:java
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 html const 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文档node
来看看引入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,能够很方便地处理异步。后端
在下面的代码中使用bluebirdapi
仍是先上代码:异步
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
返回结果后,再继续执行。async
能够看到上面的函数已经很是顺序化了,当有n
个异步函数回调时,只须要顺序写就能够啦。能够看出,其实async await
也离不开Promise
,只不过写法上消除了then
中带有callback
的那一丝丝影子,让代码更加优雅~,由于没有了then
,能够用try catch
进行错误处理函数
小彩蛋来啦,正好结合这个例子,为方便实时看到每一步的执行结果,推荐一个VSCode
插件:Quokka.ja
能够实时地进行代码的执行结果,不再用console.log
以后去看终端了。固然,在实际开发中可能应用性不是特别强,尤为是对于上下文强依赖型、后端请求依赖型的场景。