JavaScript回调函数未按预期执行

时间:2018-12-25 05:12:26

标签: javascript event-loop

根据此堆栈溢出answer

  

作为参数传递的函数始终是回调,即使目的是同步调用该函数...

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

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,据我推断,只有触发某些“事件信号”(如setTimeout)的回调函数才会被推入此类队列,但我找不到具体的参考支持吗?

2 个答案:

答案 0 :(得分:1)

“回调”通常与异步过程(如ajax请求或附加到ui的事件处理程序)结合使用。在这种情况下,我们称它们为“回调”,因为它们需要在其他操作之后执行,并且很明显,在异步过程完成或触发后,程序的逻辑将在何处取回该“调用”,从而使我们在这里“返回”。

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

您的代码没有做任何事情来中断代码的同步流。此代码段显示了即使我们添加了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);

答案 1 :(得分:0)

这不一定意味着每个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函数将在console.log函数中的第二个myfun之后输出。我建议您看一下MDN以及此good explanation的调用堆栈,事件循环和任务队列。希望这会有所帮助。