14

我写了很多看起来像这样的模块:

function get(index, callback) {
    if (cache[index] === null) {
        request(index, callback); // Queries database to get data.
    } else {
        callback(cache[index]);
    }
}

注意:这是我实际代码的简化版本。

该回调要么在同一次执行中被调用,要么在一段时间后被调用。这意味着模块的用户不确定首先运行哪个代码。

我的观察是这样的模块重新引入了以前由 JavaScript 引擎解决的多线程的一些问题。

问题:我应该使用process.nextTick还是确保在模块外调用回调是安全的?

4

2 回答 2

12

这完全取决于您在回调函数中所做的事情。如果您需要确保回调在返回时尚未触发get,您将需要process.nextTick流程;在许多情况下,您并不关心回调何时触发,因此您无需延迟其执行。不可能给出适用于所有情况的明确答案;总是将回调推迟到下一个分时应该是安全的,但这样可能会效率低一些,所以这是一个权衡。

我能想到的唯一需要将回调推迟到下一个滴答声的情况是,如果您确实需要在调用 to之后get但在调用to 之前为它设置一些东西callback。这可能是一种罕见的情况,也可能表明需要改进实际的控制流程;你不应该完全依赖于你的回调何时被调用,所以无论它使用什么环境都应该已经在get调用的地方设置好了。

在基于事件的控制流(与基于回调的相反)中存在一些情况,您可能需要推迟实际的事件触发。例如:

function doSomething() {
    var emitter = new EventEmitter();
    cached = findCachedResultSomehow();
    if (cached) {
        process.nextTick(function() {
            emitter.emit('done', cached);
        });
    } else {
        asyncGetResult(function(result) {
            emitter.emit('done', result);
        });
    }
    return emitter;
}

在这种情况下,您需要在缓存值的情况下推迟发出,因为否则事件将在调用者doSomething有机会附加侦听器之前发出。使用回调时,您通常不会有此考虑。

于 2012-10-26T10:31:37.350 回答
8

http://blog.izs.me/post/59142742143/designing-apis-for-asynchrony

如果您在内部进行回调,请执行合适的操作

如果您正在创建其他人使用的模块,则异步回调应该始终是异步的。

于 2013-12-10T13:09:51.887 回答