同步函数与异步函数混用可能造成的问题

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值