callback是Nodejs里最经典写法
const fs = require('fs')
const fileName = 'hello.md'
function fsReadFile (file, cb) {
fs.readFile(file, 'utf8', function(err, data) {
if (err == null) {
// console.log(data)
// return data
cb(true)
} else {
// return err
console.log(err)
cb(false)
}
})
}
因为readFile就异步函数,所以想在function里return的都是徒劳。必须用cb(callback的简写)来接收回调,但是这样会引入一个经典的问题,就是回调地狱。
伟大的人类发明了链式调用(promise)来解决它,那么callback怎样转成promise呢?
有两种方法:
方法1、利用new Promise来构建
function promiseReadFile1 (file) {
return new Promise((resolve, reject) => {
fsReadFile(file, cb => {
if (cb) {
resolve(cb)
} else {
reject()
}
})
})
}
再通过以下方法调用就可以
promiseReadFile1(fileName)
.then(r => {
console.log(r)
})
.catch(e => {
console.log(e)
})
方法2、利用util所带的promisify来构建
const { promisify } = require('util')
const promiseReadFile2 = promisify(fs.readFile)
promiseReadFile2(fileName, 'utf8')
.then(result => console.log(result))
.catch(err => console.log(err))
有没有更直观些的方法呢?伟大的人类又发明了yield
function* fsReadFileYield(file) {
yield promiseReadFile1(file)
}
调用方法1
const v = fsReadFileYield(fileName).next().value
v.then(r => {
console.log(r)
})
调用方法2
这里yield前要加上return,要不链式调用时then中没有值返回
const co = require('co')
function* fsReadFileYield(file) {
return yield promiseReadFile1(file)
}
co(fsReadFileYield(fileName)).then(function (r) {
console.log(r)
}).catch(function (err) {
console.log(err)
})
或者
#串行调用
function fsReadFileYieldPlus(file) {
co(function* () {
const prfRet = yield promiseReadFile1 (file)
console.log(prfRet)
const prfRet1 = yield promiseReadFile1 (file)
console.log(prfRet1)
})
}
fsReadFileYieldPlus(fileName)
那还有没有更简便的方法?async和await这对好基友诞生了
async function asyncFsReadFile (file) {
const rets = await promiseReadFile1(file)
console.log(rets)
return rets
}
asyncFsReadFile(fileName)
如果你想直接打印return的值,如以下写法
const r = asyncFsReadFile(fileName)
console.log(r)
你会得到一个
Promise {<pending>}
可以这样玩
async function fn2 (file) {
const rets = await asyncFsReadFile(file)
console.log(rets)
}
fn2(fileName)
记住有await的地方必须有async,但是有async的地方不一定有await,因为async是一个强大的npm包,可以做流程控制,如串行、并行或两者混合的流程控制。