Javascript 回调函数未按预期执行

Javascript callback function not executing as intended

根据这个 Whosebug

functions passed as parameters are always callbacks, even if the intention is that the function is called synchronously...

而且我已经了解了事件循环机制,它基本上说回调函数被推入等待队列并在同步代码完成(堆栈为空)后执行,但是在下面的代码中

function myfun(a, b, callback) {
    console.log(a);
    callback();
    console.log(b);
}

function cb() {console.log('hi')}

myfun(1, 2, cb)   // result: 1 hi 2

结果不是我预期的 1 2 hi,从中我推断只有触发一些 'event signal' 的回调函数,如 setTimeout 才会被推入这样的队列,但我不能'找不到具体的参考资料来支持它?

并不一定意味着每一个callback都是asynchronous一定要放入某个task queue执行一次synchronous个代码段(调用堆栈为空)完成。处理 Promise 的回调函数是 task queue 的候选函数。例如你的情况; cb 函数简单地以同步方式运行;这样结果就是 1 hi 2 如您所指;但是,如果我们按如下方式修改您的代码:

function myfun(a, b, callback) {
    console.log(a);
    window.setTimeout(callback, 0);
    console.log(b);
}

function cb() {
    console.log('hi');
}

myfun(1, 2, cb)   // result: 1 2 hi

这将导致 1 2 hi。即使我将超时设置为 0 毫秒; cb 函数将在 myfun 函数中的第二个 console.log 之后输出。我建议您查看 MDN and this good explanation 的调用堆栈、事件循环和任务队列。希望这会有所帮助。

"Callbacks" 通常与异步进程结合使用,例如 ajax 请求或附加到 ui 的事件处理程序。在这些情况下,我们称它们为 "callbacks",因为它们需要在其他事情之后执行,并且很明显,在异步过程完成或触发后,程序的逻辑将在哪里恢复这个 "call" "back" 这里。

您可以使用 setTimeout() 添加到事件循环堆栈。使用承诺,您可以在等待异步过程完成时调用事件循环中的堆栈。

您的代码没有做任何事情来中断代码的同步流。这个片段展示了即使我们添加了一个应该延迟操作的超时 0,我们仍然可以等待一个允许事件循环堆栈到 运行.

的承诺。

function myfun(a, b, callback) {
  console.log(a);
  callback();
  console.log(b);
}

function cb() {
  console.log('hi')
}

myfun(1, 2, cb) // result: 1 hi 2

// same behavior as above

function myStaticFun() {
  console.log(1);
  cb();
  console.log(2);
}

myStaticFun();

// now same as before using a promise to wait a moment and the event loop stack is invoked during the pause

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function myEventLoopInvokingFun(a, b, callback) {
  console.log(a);
  setTimeout(callback, 0)
  await sleep(0);
  console.log(b);
}

myEventLoopInvokingFun(1, 2, cb);