这个例子是JavaScript,因为那是我主要使用回调的地方。我想了解他们的工作水平如何。
在下面的例子中,我希望一切都按顺序发生,并且“回调”发生在“第3步”之后和“第4步”之前。这对我来说很有意义,因为一切都是按照单个执行线程完成的。没有诡计。唯一有点特别的是你已经将一个函数传递给了另一个函数。
function main() {
console.log("step 1");
console.log("step 2");
doSomething(myCallBack);
console.log("step 4");
}
function doSomething(f) {
accessTheDatabase(); // this could take a while
console.log("step 3");
f(); // done - now call back
}
function myCallBack() {
console.log("calling back!");
}
如何使doSomething
异步,以便“步骤4”可以在“步骤3”之前或与之并行执行?
我假设如果以某种方式异步调用doSomething
,它必须在不同的线程上,不是吗?如果是这样,当它完成然后调用myCallBack
时,是否会在第二个线程或主线程上发生回调?如果它发生在主线程上,为什么第二个线程甚至需要一个指向回调函数的指针?线程间调用如何工作?
答案 0 :(得分:11)
window.setTimeout(doSomething, 0, myCallBack);
这有效地将调用doSomething(myCallBack)
置于定时器队列中,并且在经过0或更多毫秒之后,最终将调用它。但是,与JavaScript中的所有异步调用一样,必须在调用任何异步回调之前放弃执行上下文;也就是说,在doSomething(myCallBack)
函数完成之前,不会处理计时器队列(因此不会调用main()
,假设这是JavaScript的结束。
这种基于setTimeout
的方法的一个不幸后果是doSomething(myCallBack)
并未与console.log("step 4")
并行调用。另一方面,考虑XMLHttpRequest.send;在进行此调用之后,您的JS的其余部分可以在浏览器发出HTTP请求时继续执行。您的脚本确实需要在onreadystatechange处理程序执行之前完成执行,但大多数HTTP连接工作可以在JS执行时并行执行。
答案 1 :(得分:5)
嗯...看起来有些不对劲(我已经做了很少的JavaScript):你将myCallBack传递给函数doSomething()但是你没有回复它!?您必须在doSomething()中调用f()或将其传递给另一个函数,该函数将在您的长操作完成后调用它。并且没有回调本身不是异步的 - 在您的情况下,您正在运行它在同一个线程上(即使accessTheDatabase()是异步的,在这种情况下它会立即返回!) - 所以它仍然会进入Step1,Step2,Step3,Step4。我相信你想要:
function main() {
console.log("step 1");
console.log("step 2");
doSomething(myCallBack);
console.log("step 4");
}
function doSomething(f) {
accessTheDatabase(f); // assuming this is an asynchronous operation and calls the callback f once done
}
function myCallBack() {
console.log("step 3");
}
回答问题的第二部分:回调将在你从调用它的线程上运行 - 在另一个线程上运行回调你必须加入()首先是线程然后调用()或者startinvoke()回调 - 虽然可能已经有一些内置的方法将你的回调调度到要在其运行的线程上运行的事物队列(通常是UI线程的情况) )注意:可能已经是accessTheDatabase()确实在调用它的线程上运行回调 - 使用前面提到的方法之一......
答案 2 :(得分:0)
你需要多个执行线程才能做到这一点,我不相信你可以用Javascript做(虽然如果我错了,请纠正我)。但是,如果您正在编写C / C ++程序,请查看pthreads包(或Mac OS X 10.6上的libdispatch)。
编辑:谷歌搜索“线程javascript”会产生一些可能有趣的结果。
答案 3 :(得分:0)
使用回调方式(函数声明名称或函数表达式变量名称作为另一个函数的参数),它们是同步。要使它们异步,您可以将它们包装在setTimeout
。