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

  • Post author:
  • Post category:其他


定义一个函数, 该函数会

读取文件内容

, 并将文件内容

存入 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设计模式-第三版> 第三章-回调与事件



版权声明:本文为qq_30763385原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。