定义一个函数, 该函数会
读取文件内容
, 并将文件内容
存入 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设计模式-第三版> 第三章-回调与事件