题外话,有网友问为什么公众号叫【背井】?这里解释一下:
【背井】 的 【背】 读第一声,指背着井,和【坐井观天】里的【井】是同一口井,作为对自己的警醒。
有些人觉得自己经历了一些事,不会再是 井底之蛙 了,其实他们不过是把井从 脚底 换到 背上 了而已。人还是那个人。
回到正题。
写的项目也不少了,但回想起来,实际工作中并没有用过 process.nextTick()
方法(不排除第三方库会用到)。好奇的我于是从网上查了查到底何时要用它,下面是我找到的 2 个相对满意的答案:
1在 EventEmiter
子类的构造方法中使用
比如,当我们需要在 EventEmiter
实例化后立即发送一个事件(比如 init
),代码可以这样写:
class MyEmitter extends EventEmitter {
constructor() {
super();
// 实例化之后立即发送 init 事件
process.nextTick(() => {
this.emit('init');
});
}
}
// 使用
const myEmitter = new MyEmitter();
myEmitter.once('init', () => {
console.log('init done!');
});
如果不使用 process.nextTick()
而是直接在构造器中调用 this.emit()
,后面的 once()
调用并不能捕获到构造器中的 init
事件,因为在实例构造过程中,once
监听器还没来得及注册。
有疑问的童鞋可以试运行下面的代码:
class MyEmitter extends EventEmitter {
constructor() {
super();
// 实例化之后立即发送 init 事件
this.emit('init');
}
}
// 使用
const myEmitter = new MyEmitter();
// 在注册该监听器之前,上面的 emit 就已经发送完成了
// 所以监听不到构造器方法中产生的事件
myEmitter.once('init', () => {
console.log('init done!');
});
2保持函数的异步性
一个好的实践是,一个方法要么是同步的,要么是异步的,混用常常会产生意想不到的效果。
比如下面这个方法:
function maybeSync(arg, cb) {
if (arg) {
// 同步调用
cb();
return;
}
// 异步调用
fs.stat('file', cb);
}
该方法既可能是同步的也可能是异步的(取决于参数 arg
的值),当使用时:
const maybeTrue = Math.random() > 0.5;
maybeSync(maybeTrue, () => {
foo();
});
bar();
你无法判断 foo()
和 bar()
谁先执行,让代码难以推理(reason about)。
一个解决办法是,通过 process.nextTick()
让 maybeSync()
完全变成异步的:
function definitelyAsync(arg, cb) {
if (arg) {
process.nextTick(cb);
return;
}
fs.stat('file', cb);
}
这样一来,我们可以肯定地说,bar()
是先于 foo()
执行的。
3另一个疑问
有童鞋可能要问 process.nextTick()
到底什么时候执行?
简单点,可以这么说:当所有同步方法执行完后,最先被执行的就是 process.nextTick()
里的回调方法。基于此点,process.nextTick()
还有一个坑(gotcha):如果你递归调用 process.nextTick()
,eventloop 就再也没机会执行其它的方法了。
原文始发于微信公众号(背井):process.nextTick()的两个用途
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/246663.html