回调,高阶函数和回调队列之间有什么区别

时间:2018-07-29 10:35:25

标签: javascript callback functional-programming

在这一点上,我有一个问题,确切地说是回调是什么,它与高阶函数有何不同以及它与该概念有何关系回调队列

来自MDN:Callback function

  

回调函数是作为参数传递给另一个函数的函数,然后在外部函数内部调用该回调函数以完成某种例程或操作。

看起来高阶函数的定义存在重叠。一个传递给(然后被调用)另一个函数的函数。

这是回调的MDN示例:

function greeting(name) {
  alert('Hello ' + name);
}

function processUserInput(callback) {
  var name = prompt('Please enter your name.');
  callback(name);
}

processUserInput(greeting);

毫无疑问,到目前为止。

然后我遇到了事件循环回调队列的想法。

 console.log("me first");

  setTimeout(function asyncLog() {
       console.log("i am the last")
  }, 2000);

  console.log("me second")

产生seTimeout函数,实际上是一个JavaScript包装器,它与Web浏览器API(计时器)相互连接。 setTimeout将一个函数(asyncLog)和一个计时器(2000ms)传递给Timer API。

当计时器功能(在网络浏览器中)完成其工作后,将在asyncLog中发送函数callback queue并准备在JS调用堆栈中立即在调用堆栈中调用(1)为空,(2)在全局执行上下文中处理了所有内容。

因此,在处理了最后一行console.log("me second")之后,事件循环将回调函数asyncLog从回调队列传递到调用堆栈,并执行它。

最终订单是:

me first
me second
i am the last

在第一个示例中,即使我们将greeting称为“回调”函数,但我的理解表明,回调队列的整个机制都被完全跳过了:我们没有做任何异步的事情,不要与Web浏览器API交互(一切都包含在JS中)。

如果是这样,当它们与回调队列和异步世界无关时,为什么将传递给其他函数的函数称为回调(而不是简单的高阶函数)?

2 个答案:

答案 0 :(得分:4)

higher-order function是一个将另一个函数作为参数的函数,和/或将函数返回给其调用方。

callback function是一个传递给另一个函数的函数,期望另一个函数会调用它。

因此,回调本身不一定是高级函数,而是将回调作为参数接收的函数。考虑一个非常常见的情况,即DOM事件侦听器:

elem.addEventListener('click', console.log);

在这里,.addEventListener是一个高阶函数,它采用另一个函数(console.log)然后调用该函数。尽管console.log是这里的回调,但在这种情况下它本身并不充当高阶函数。

事件循环是基础运行时向您公开的一种机制。在这里,我们将想象我们必须使用数组作为队列来手动执行此操作:

const queue = [];
const setTimeout = (f, ...args) => {
  queue.push([f, args]);
};

const runQueuedCallbacks = () => {
  let queued;
  while (queued = queue.shift()) {
    let [f, args] = queue;
    f(...args);
  }
};

setTimeout(console.log, 'first');   // queues a call to log
setTimeout(console.log, 'second');  // queues a call to log
console.log('zero-th');             // directly calls log, prints first

// at this point there's no more code to execute, so runQueuedCallbacks runs
// and sequentially steps through the enqueued callbacks.

在现实生活中,由于诸如微任务解析(这在排队的回调将另一个回调排队时会发生什么?)之类的事情,所以这有点复杂,但这希望应该能为您提供一个不错的画面。

答案 1 :(得分:-1)

高阶函数是将另一个函数作为参数和/或将函数返回给其调用者的函数。在此,作为参数传递的函数称为回调函数。 但是,回调函数也可以是高阶函数,也可以不是。让我们看看示例。

function printString(callbackHof, callback_only, str) {
   str +=' concated first';
  callbackHof( callback_only,str);
}

function concatFirst(callback_only, str)
{
  callback_only(str);
}

function concatAgain(str)
{
  str += ' contated again';
  console.log(str);
}

printString(concatFirst, concatAgain, 'anything');

为澄清起见,输出为=“先合并再合并的任何内容”。

这里printString()是一个高阶函数,它使用两个函数和一个字符串作为参数。 printString()的函数参数为concatFirst()和concatAgain(),这些concatFirst()和concatAgain()函数根据定义是回调函数。

在这里,concatFirst()既是回调函数又是高阶函数,因为它作为printString()的参数传递,然后还使用concatAgain()回调函数作为其自己的输入。

而且,concatAgain()只是一个回调函数,因为仅使用字符串参数调用而没有其他函数参数。

最后,回调队列是浏览器或JavaScript编译器遵循的机制,可以借助事件循环完美地执行异步和回调操作。