定义一个函数, 该函数会读取文件内容, 并将文件内容存入 cache 中
文件读取分为两种可能性
- 未读取过: 读取文件内容, 并存入
cache
(异步操作) - 读取过: 从
cache
中取出 (同步操作)
function inconsistentRead(filename, cb) {
if (cache.has(filename)) {
// 同步执行
cb(cache.get(filename))
} else {
// 异步执行
const callback = (err, data) => {
cache.set(filename, data)
cb(data)
}
readFile(filename, 'utf8', callback)
}
}
⭐️ 异步执行代码意味着, 将当前事件
添加到事件队列
中, 并立即返回
当事件完成后, 执行对应回调函数
从上面函数中可以知道, readFile
为异步函数, 当读取到文件内容时, 会执行callback(回调函数)
, 而 callback 函数
内部有个外界传入的 cb
函数, 也就是说: ⭐️ callback 函数
具体执行的实际代码, 可在之后定义
所以说, 异步代码
可以做到回调函数具体执行代码
在实际调用之后定义, 而同步代码
做不到, 运行到哪里, 就立马执行
createFileReader
调用一个同步异步混用的读取文件的函数, 并给其传入一个回调函数: 遍历 listeners
中所有的listener(监听器)
listener
: 通过 onDataReady
方法添加的
import { readFile } from 'fs'
const cache = new Map()
function inconsistentRead(filename, cb) {
if (cache.has(filename)) { // <----- 文件名存在于缓存中,同步执行
cb(cache.get(filename))
} else { // <----- 文件名不存在缓存中,读取文件,异步执行
readFile(filename, 'utf8', (err, data) => {
cache.set(filename, data)
cb(data)
})
}
}
function createFileReader(filename) {
const listeners = []
inconsistentRead(filename, value => {
listeners.forEach(listener => listener(value))
})
return {
onDataReady: listener => listeners.push(listener)
}
}
// cache 中无 data.txt, 执行 readFile,在 cb 执行之前可为其添加 listener
const reader1 = createFileReader('data.txt')
// 给异步函数回调注册具体执行代码
reader1.onDataReady(data => { // 添加 listener 到 listeners
console.log(`123 call data: ${data}`)
})
reader1.onDataReady(data => { // 添加 listener 到 listeners
console.log(`456 call data: ${data}`)
})
reader1.onDataReady(data => { // 添加 listener 到 listeners
console.log(`789 call data: ${data}`)
const reader2 = createFileReader('data.txt') // <------ 读取相同的文件,此时,cache 存在,执行同步方法
// 给异步代码添加的具体执行代码, 对同步代码来说, 无意义(因为已经执行过了), 根本不会执行
reader2.onDataReady(data => {
console.log(`Second call data: ${data}`)
})
})
输出结果如下: reader2.onDataReady
内的回调未执行
所以, 一个函数中, 要么全是同步, 要么全是异步
同步读取函数
function consistentReadSync (filename) {
if (cache.has(filename)) {
return cache.get(filename)
} else {
const data = readFileSync(filename, 'utf8')
cache.set(filename, data)
return data
}
}
console.log(consistentReadSync('data.txt'))
console.log(consistentReadSync('data.txt'))
异步读取函数
import { readFile } from 'fs'
const cache = new Map()
function consistentReadAsync(filename, callback) {
if (cache.has(filename)) {
process.nextTick(() => callback(cache.get(filename)))
} else {
// asynchronous function
readFile(filename, 'utf8', (err, data) => {
cache.set(filename, data)
callback(data)
})
}
}
function createFileReader(filename) {
const listeners = []
consistentReadAsync(filename, value => {
listeners.forEach(listener => listener(value))
})
return {
onDataReady: listener => listeners.push(listener)
}
}
const reader1 = createFileReader('data.txt')
reader1.onDataReady(data => {
console.log(`123 call data: ${data}`)
})
reader1.onDataReady(data => {
console.log(`456 call data: ${data}`)
})
reader1.onDataReady(data => {
console.log(`789 call data: ${data}`)
const reader2 = createFileReader('data.txt')
reader2.onDataReady(data => {
console.log(`Second call data: ${data}`)
})
})
来自 <Nodejs设计模式-第三版> 第三章-回调与事件