我在理解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
只是另一个同步函数。有人能帮我理解我在这里俯瞰的东西吗?谢谢!
答案 0 :(得分: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);
它基本上意味着“当你不忙时尽快运行这个功能”。
答案 1 :(得分:2)
编辑:我刚才意识到问题是用node.js标记的。我的答案更多是关于浏览器中的Javascript,@ hexacyanide的答案更多是关于node.js.不过我想知道两者都没有受伤!
你发布它的方式代码确实会阻塞。对于异步行为,您可以使用一些内容,例如
setTimeout
和setInterval
FileReader
API 您的示例代码可以编写如下(fiddle):
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