《node.js设计模式》学习笔记——同步异步调用问题

避免Zalgo

Zalgo: 一种 JavaScript 开发人员虚构的疯狂恶魔,取名 Zalgo,用来描述 JavaScript 中同步 / 异步的混乱。Zalgo是一个互联网传说,会导致世界错乱,死亡和毁灭的一个不详实体。

有兴趣的同学可以在如下网址上找到Isaac Z. Schlueter的原始帖子
https://blog.izs.me/2013/08/designing-apis-for-asynchrony

不可预测的危险的函数

我们来看一下下面这个危险的函数,它希望实现的目的是如果没有缓冲是异步读取文件,如果有缓存则同步读取缓存。请大家注意,这并不是一个好的实践。它的行为是难以预测的。

const fs = require('fs')
const cache = {}
function inconsistentRead(filename, cb) {
	if (cache[filename]) {
		// 同步调用!!!
		cb(cache[filename])
	} else {
		// 异步调用!!!
		fs.readFile(filename, 'utf8', (err,data) => {
			cache[filename] = data
			cb(data)
		})
	}
}

解决上述的问题

我们需要明确,API明确定义其特性:同步的或者是异步的

使用同步API

使用fs.readFileSync()函数替代其异步函数,使其变成纯同步函数,代码如下:

const fs = require('fs')
const cache = {}
function consistentRead(filename) {
	if (cache[filename]) {
		return cache[filename]
	} else {
		// 改用同步读取文件
		cache[filename] = fs.readFileSync(filename, 'utf8')
		return cache[filename]
	}
}

当然使用同步API代替异步API有如下注意事项:

  1. 用于特定功能的同步API可能并不总是可用的

  2. 同步API将阻塞事件循环,打破了JavaScript并发模型,是整个应用程序变慢。

    在Node.js中很多情况下都不建议使用同步I/O, 然而,在某些情况下,这可能是最简单和最有效的方案。所以我们需要评估不同的应用场景,来选择不同的方案。
    如果静态文件的数量有限,可以使用同步影响不大,在启动应用程序时,使用同步阻塞加载配置文件也是比较好的选择。如果必须一次性读取许多文件,那就不一样了。

使用异步,延迟执行

使用process.nextTick()来延迟执行以实现异步执行回调

const fs = require('fs')
const cache = {}
function inconsistentRead(filename, cb) {
	if (cache[filename]) {
		// 使用process.nextTick() 延迟一个函数异步执行
		process.nextTick(() => cb(cache[filename]))
	} else {
		fs.readFile(filename, 'utf8', (err,data) => {
			cache[filename] = data
			cb(data)
		})
	}
}

process.nextTick() 的功能非常简单,就是将回调函数作为参数,并将其推到事件队列的顶部,在任何等待处理的I/O事件之前返回,一旦事件循环再次运行,该回调将被执行。

我们依然需要注意一个问题,如果在递归调用process.nextTick() 的时候,会导致I/O饥饿的问题,这个情况下,我们可以采用setImmediate()来替代。他们的作用虽然非常相似,但是语义却完全不同,process.nextTick() 延迟回调在任何其他I/O事件触发之前运行,setImmediate()的回调执行将在队列中已有的任何I/O事件之后排队。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值