題外:今天嘗試了一下從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
以後去看終端了。固然,在實際開發中可能應用性不是特別強,尤爲是對於上下文強依賴型、後端請求依賴型的場景。