本文不是概念性文章,只是經過一個例子來看看操做異步的一些手段.html
先看一個例子:node
const fs = require('fs')
fs.readFile('./file.txt', 'utf-8', (err, res) => {
console.log(res)
})
複製代碼
經過 node 提供的 fs.readFile 方法打印出file.txt
的內容.json
若是readFile
能夠經過 promise 方式調用就行了, 像下面這樣:api
readFile('./file.txt', 'utf-8').then(res => {
console.log(res)
})
複製代碼
如今咱們將 callback 形式的方法調用 轉成 promise 形式的調用,這個過程也成爲 promisifypromise
const promisify = fn => (...args) =>
new Promise((reslove, reject) =>
func(...args, (err, result) => (err ? reject(err) : resolve(result)))
)
複製代碼
固然,在 node 8 及其以上版本,能夠使用util.promisify異步
如今就能夠這樣作啦async
const fs = require('fs')
const readFile = promisify(fs.readFile)
readFile('./file.txt', 'utf-8').then(res => {
console.log(res)
})
複製代碼
統一的 API,線性的調用方式,更爲靈活的異步控制,exciting!函數
ES7(ECMAScript 2016)推出了 Async 函數(async/await),實現了以順序/同步代碼的編寫方式來控制異步流程.再來一遍post
const fs = require('fs')
const util = require('util')
const readFile = util.promisify(fs.readFile)
;(async () => {
const res = await readFile('./package.json', 'utf-8')
console.log(res)
})()
複製代碼
相較於 promise,async/await 更易理解. 若是你聽過大名鼎鼎的 co,則會發現這兩者使用方式是多麼類似啊!優化
const co = require('co')
const fs = require('fs')
const util = require('util')
const readFile = util.promisify(fs.readFile)
co(function*() {
const res = yield readFile('./package.json', 'utf-8')
console.log(res)
})
複製代碼
不過這並非什麼黑魔法,繼續向下看.
首先咱們須要一點 generator 的知識,你能夠看Generator-MDN
若是你不想看,看下 demo 也能夠
demo 1
function* generatorFn() {
yield 1
yield 2
yield 3
}
const it = generatorFn()
console.log(it.next()) // { value: 1, done: false }
console.log(it.next()) // { value: 2, done: false }
console.log(it.next()) // { value: 3, done: false }
console.log(it.next()) // { value: undefined, done: true }
複製代碼
demo 2
function* generatorFn() {
const a = yield 1
console.log(a) // hhh
yield 2
yield 3
}
const it = generatorFn()
console.log(it.next()) // { value: 1, done: false }
console.log(it.next('hhh')) // { value: 2, done: false }
console.log(it.next()) // { value: 3, done: false }
console.log(it.next()) // { value: undefined, done: true }
複製代碼
弄清楚代碼執行順序便可。
const fs = require('fs')
const util = require('util')
const readFile = util.promisify(fs.readFile)
function go() {}
go(function*() {
const file1 = yield readFile('./file1.txt', 'utf-8')
console.log(file1)
const file2 = yield readFile('./file2.txt', 'utf-8')
console.log(file2)
})
複製代碼
思路很簡單,咱們只要在 go 中接住 yield 拋出來的 promise,註冊好"解決函數"(resolver),在 resolver 內部將執行結果塞進去便可.
先寫一個最挫的,只能玩 2 層,和咱們的代碼綁定的死死的.
function go(gen) {
const it = gen()
const p1 = it.next().value
p1.then(res => {
const p2 = it.next(res).value
p2.then(res => {
it.next(res)
})
})
}
複製代碼
很明顯,能夠優化一波
function go(gen) {
const it = gen()
const run = p => {
p.then(res => {
const { value, done } = it.next(res)
if (done) {
// 若是結束了就返回
return value
}
run(value)
})
}
const { value, done } = it.next()
if (done) {
return value
}
run(p1)
}
複製代碼
本文到此爲止,代碼很粗糙,下一篇文章拿 co 源碼來讀讀。
推薦閱讀: