我来自 PIC 汇编语言编程,程序通常连续运行。我现在已经学习 JavaScript 很长一段时间了,但是当回调函数作为调用异步函数的参数给出时,我对它们的使用有点受阻。我确实意识到回调已经被“永远”解释了,但我已经从头到尾读了大约 10 本书,但没有得到明确的答案。
首先,大多数描述都“掩盖”了异步函数在代码中的实际实现方式。我现在发现这通常不是 Javascript 的一部分,而是底层主机代码(浏览器,甚至可能是浏览器运行的操作系统)的一部分。但是 Javascript 必须有一种机制来运行本身不属于 Javascript 语言一部分的函数,并且底层主机必须有一种允许 Javascript 继续运行的机制。我从未见过任何这方面的代码。我想知道主机代码到底是如何将特定的 Javascript 块放入事件队列中的?这一切看起来都相当安静。
当谈到回调的使用时,我有以下假设(以此类推),结果证明是错误的。 我正在做饭,需要一些盐,但我没有。我派朋友去买一些盐,但我不想停止做饭。所以我的异步函数是 goBuySomeSalt(nameOfShop, putItOnTable)。我继续做饭,并期望盐稍后到达(然后放入 putOnTable())。当盐到达时,我会在烹饪中使用它。
Javascript 似乎不允许这样做。回调的解释几乎普遍表示,当异步函数完成时,将会调用回调。所以当我的朋友回来时我想用我的盐。但我不能,因为我还在做饭。在我完成烹饪之前似乎无法使用盐,因为我的朋友在活动队列的后面等待,只有当我完成我正在做的事情时,他们才会把盐放在桌子上。 因此我对盐的要求基本上是无用的。 我错过了什么吗?我可以在烹饪过程中“轮询”盐吗?盐到货后可以通知我吗? (请注意;我已经读过有关承诺等的内容)
下面是我的代码来说明这一点:
function a(){
setTimeout(d, 1000);
console.log ("Please fetch some salt!")
}
function d(){ console.log("Here's your salt - sorry I'm too late");}
a();
for (let i = 0; i < 4000000000; i++) {
if (i%1000000000 == 0) { console.log ("Cooking");}
}
console.log ("finished cooking - but used no salt!!")
输出的顺序是:
“请拿点盐来!” “烹饪” “烹饪” “烹饪” “烹饪” “煮好了——但是没有放盐!!” “这是你的盐 - 抱歉我来晚了”
函数是一等公民,因此每个函数都被视为一个单独的范围,并在返回输出之前在其内部进行完全处理。
例如:
function a() { console.log("hello"); }
function b(c) {
console.log("good bye");
c();
}
b(a) 将导致
good bye
hello
这是因为函数 b 中首先调用 b,然后调用 a
现在 - 如果我们这样做:
setTimeout(a,0);
setTimeout(b(a), 0);
结果应该
是 你好 再见 你好 但实际上是
good bye
hello
hello
这是因为每个函数在移动到下一个函数之前都会完全评估其状态,在这种情况下,b(a) 是一个函数,而不是只是一个函数引用的 a
现在如果我们这样做:
setTimeout(a(),0);
setTimeout(b(a), 0);
结果符合预期:
hello
good bye
hello
这是因为 a() 现在是一个函数,这导致它在 b(a) 之前完全执行。
因此,这完全取决于回调是函数、指针还是其他东西,以及它们发生的顺序,并且每个函数在移动到下一个函数并更新状态之前都会被完全评估。
希望这有帮助