0

我在理解 JS 回调的机制时遇到了一些麻烦。我很清楚如何在 JS 中使用回调,但我不明白回调是如何异步的。

例如,如果我的理解是正确的,回调的性质是:

db.query(param1, param2 , callback_fn1(){..} );

db.query() 的实现如下:

 db.prototype.query = function(p1 , p2 , callback ){
      //some code 
      callback();
}

上面的实现是怎么做db.query一个异步函数的呢?这是否意味着一个被调用的函数callback被传递给query并且该函数在内部被调用query?看起来query只是另一个同步函数。有人可以帮我理解我在这里忽略了什么吗?谢谢!

4

2 回答 2

3

您显示的代码示例实际上仍然是同步的,因为被指示立即运行。异步回调是不需要立即执行的回调,因此在您指示它运行之前它不会阻塞事件循环。

Node.js 中最常见的方法是process.nextTick()在事件循环调用堆栈为空时运行指定的函数。这是一个例子:

var async = function(args, callback) {
  // do some work
  process.nextTick(function() {
    callback(val);
  });
};

然后我们这样调用函数:

async(args, function(val) {
  console.log(val);
});
console.log('end');

在本例中,函数async()console.log('end')被添加到调用堆栈中。一旦这两个函数都运行,调用堆栈就会清空,一旦它为空,console.log(val)就会运行。

如果您仍然感到困惑,请将其process.nextTick()视为此代码的优化版本:

var fn = function() {};
setTimeout(fn, 0);

它的基本意思是“在你不忙的时候尽快运行这个功能”。

于 2013-09-29T16:46:41.953 回答
2

编辑:我刚刚意识到这个问题是用 node.js 标记的。我的回答更多关于浏览器中的 Javascript,@hexacyanide 的回答更多关于 node.js。不过,我想知道两者并没有什么坏处!

您发布代码的方式确实会阻塞。对于异步行为,您可以利用一些东西,例如

  • setTimeoutsetInterval
  • 内置的异步方法,例如来自FileReaderAPI
  • Ajax 请求
  • 网络工作者(见@html5rocks

您的示例代码可以编写如下(小提琴):

function doStuff(callback) {
    setTimeout(function () {
        for (var i = 0; i < 1000; i++) {
            // do some busy work
            var x = Math.sqrt(i);
        }

        callback();
    }, 0);
}

console.log('start');
doStuff(function () {
    console.log('callback called');
});
console.log('after doStuff()');

setTimeout调用将允许 Javascript 解释器/编译器(无论它们现在如何工作)以非阻塞方式运行该函数,这就是为什么(很可能),您将看到输出

start
after doStuff()
callback called

请注意,异步与多线程不同。Javascript 仍然是单线程的(网络工作者除外!)。

例如here可以找到更深入的解释

于 2013-09-29T16:44:23.657 回答