什么是延迟回调?


15

我了解回调的概念,在回调中,我将一个函数传递给另一个函数,然后该函数随便使用提供的函数。

即使在谷歌搜索之后,我仍在努力理解延迟的回调。

有人可以提供简单的解释吗?我使用Ruby编程,但也了解C / C ++,但最重要的是,我是一位经验丰富的汇编语言程序员。所以我想知道这是否有点像一堆被弹出的回调地址?我希望学习jquery或node.js,而这些延迟的回调似乎对两者都是必不可少的。我了解基本的线程处理原理(尽管互斥对象使我的头部受伤;)


您是说jQuery的Deferred对象吗?这是有关Node.js的特定内容吗?
bfavaretto 2012年

1
不,我是说一般。尽管我确实想学习jquery甚至可能要学习node.js,但我还是觉得我需要先了解一下延迟回调实际上是什么。我阅读了有关回调的Wikipedia文章,但无法理解延迟的回调,这些回调似乎是使用这些语言的异步操作范例所固有的。


1
我确实是在要求推迟回调而不是实现的概念性想法-很抱歉,如果我没有更清楚地说明这一点。我还提供了一些语言示例来解释我要澄清的想法以及我的编程背景,以便人们知道如何提出答案。非常感谢您到目前为止的回答-我到了!
2012年

好的,我想我现在已经明白了,谢谢大家!我不知道该怎么做。卡梅伦(Cameron)最简单地解释了这个概念,这就是我真正追求的,但是其他人也加入进来,并增加了我的知识。我不确定是什么方式接受答案,因为我对此
并不陌生

Answers:


4

根据要求,以下是作为答复提出的意见:


我不确定您是否完全理解JS中的函数是一流的对象,因此可以在创建它们之前将它们存储到需要为止。

例如,假设您要写入文件,然后打印出一条日志消息;因此,您可以调用“ write()”函数(或其他函数)并将其传递给输出日志消息的函数(这是延迟的回调函数)。“ write()”在内部存储对给定函数的引用,开始写入文件,并设置其自己的回调以知道写入何时完成。然后在完成写入之前返回。如果是,则以某种方式调用内部回调(这是基础框架的工作-在node.js的情况下,它是通过事件循环完成的),然后调用您的回调以打印日志消息。

“延迟”部分只是意味着您的回调函数不会立即被调用;调用它被推迟到适当的时间。对于像node.js中的许多异步函数那样,通常在操作完成(或发生错误)时调用给定的回调。

大多数东西在node.js中是异步的,但是在带有jQuery的浏览器中,大多数东西实际上是同步的(显然,对于AJAX请求除外)。由于一流的函数在JavaScript中非常方便(尤其是由于强大的闭包支持),因此回调也可在浏览器中的任何地方使用,但对于同步操作,它们并不“延迟”(除非它们不被立即调用)您,但稍后通过您调用的函数)。

基础系统是事件驱动的,这一事实与延迟回调的使用正交。您可以想象一个(非常慢的)版本的node.js,它为每个操作启动一个线程,然后在线程完成其工作时调用给定的回调,而完全不使用事件。当然,这是一个可怕的模型,但这说明了我的观点:-)


8

延迟回调的工作方式是每次向其添加回调时,该回调将被推送到数组。然后,在延迟对象上调用.resolve()or .resolveWith()方法时,.done()将按顺序执行数组中的所有回调。

现在我们来看看什么是延迟对象。以下面的代码段为例。

var deferred = $.Deferred();
var promise = deferred.promise();

现在,我们有了一个延迟对象,以及该延迟对象的promise对象。递延对象具有所有相同的方法承诺对象,然而,许对象仅具有方法.done().fail()以及.always()其用于回调添加到针对每个相应的延迟对象event。另一方面,延迟对象还有其他几种方法,最重要的是.resolve().reject()。在延迟对象上调用这些方法时,将调用所有回调。.resolve()将触发.done().always()回调,而.reject()方法调用.fail().always()回调。

通常,延迟的对象保持隐藏在私有作用域内,并且Promise对象从函数返回,以便可以在其上放置回调。延迟的对象将在以后解析,例如在ajax请求完成之后或在加载图像之后,在setTimeout之后等等。认识到延迟的对象只能解析一次也很重要。如果已经解决,则将立即调用其回调。

这是我使用的另一个示例:

function loadImage(url) {
    var def = $.Deferred(),
        img = new Image();
    $(img).on("load error",function(e){
        if (e.type === "error") {
            def.reject(url);
        }
        else {
            def.resolve(url);
        }
    });
    img.src = url;
    // return the promise object so that callbacks can
    // be defined on the deferred object.
    return def.promise();
}
loadImage("foobar.jpg").done(function(){
    alert("The image is loaded!");
}).fail(function(){
    alert("The image failed to load!");
}).always(function(){
    alert("This is always called!");
});

有关jQuery $.Deferred()方法和延迟对象的更多信息,请访问http://api.jquery.com/category/deferred-object/


一旦我了解了延迟回调的概念,这可能是无价的。抱歉,但我仍然不明白延迟回调的概念。我正在寻找其背后的概念性想法。有点像Mihia的想法。一旦我弄清楚了,那也许我就能理解js。
2012年

3

我不确定,但是我相信延迟回调是指异步回调,因此您会因此而获得更多的Google搜索。

我发现的最佳解释是在http://www.nodebeginner.org

嘿,大概是ExpensiveFunction(),请做您的工作,但是我,单个Node.js线程,不会在这里等到您完成为止,我将继续执行您下面的代码行,因此请您继续这个callbackFunction()在这里,当您完成昂贵的工作时调用它?谢谢!”

在此示例中,ExpensiveFunction可能是非阻塞的(或异步函数)。这意味着它不会立即执行,而是放置在所谓的事件循环中。node.js线程将继续执行,但是在某个时间点,它将决定从事件循环中执行某些操作。当到达expensiveExpensiveFunction时,将对其进行调用,并且当expensiveExpensiveFunction完成执行时,它将调用作为参数传递给它的(延迟)回调。

例如,可能使用ExpensiveFunction,可以使用fs.readFile


谢谢。但是,如果昂贵的函数已经返回并且您又回到执行的主线程中,该函数将如何处理呢?我一点都不明白。您是说该功能在结束后仍会以某种方式持续存在吗?

编辑了答案,也许现在更清楚了。

非常有帮助。但是...我是否必须处理此存储的回调数组?我的意思是,处理此列表是什么。(例如)是js在后台执行这些回调而您无需执行任何操作,还是某个事件导致node.js或某些事情调用了特定的回调。抱歉,我说的话占了我的70%,但剩下的就有点失落了:)
十倍2012年

@tentimes-“正在处理此列表的是什么” $ .Deferred()对象正在处理该列表。在原始延迟对象上调用.resolve().reject()时,将调用回调列表。
user400654

2
@tentimes:从您的意思来说,我不确定您完全理解JS中的函数是一类对象的事实,因此可以在创建它们之前将其存储直到需要。例如,说您要写入文件,然后打印出一条日志消息;因此您可以调用“写入”函数(或其他函数),然后将其传递给输出日志消息的函数。“ write()”在内部存储对给定函数的引用,开始写入文件,并设置其自己的回调以知道写入何时完成。然后在完成写入之前返回。在这种情况下,将调用您的函数。
卡梅伦

3

JavaScript是单线程的,因此您无法从线程的角度来理解这一点。这是使用jQuery的常规和异步回调的示例:

var regularCallback = function(evt) {
    alert("I'm a callback!")
}
var asyncCallback = function(data) {
    alert("I only run when an async operation finishes!")
}

// Bind the regular callback to a button's click event
$('#mybutton').on('click', regularCallback);

// Start an ajax request to the server. The request is asynchronous, so code
// below this line will execute immediately. The callback function
// will only be called when the request is complete.
$.get("http://google.com", asyncCallback);

现在,这使我到某个地方,谢谢。因此,异步响应于我使用ajax设置的事件-只是将其发送出去,如果该事件发生,我的回调将被调用?我想我明白了。node.js / jquery是否会与jquery usnig延迟对象以及与之交互的复杂系统做类似的事情,实际上只是使用方法来做同样的事情?
2012年

1
@tentimes,是的!回调通常是响应事件而运行的(但由于“回调”不是js语言的构造,因此有时会在其他上下文中使用该术语)。您在凯文(Kevin)的答案中看到的延迟对象(承诺)基本上是语法糖。当某个(异步)事件被触发时,它们将得到“解决”或“拒绝”,然后调用适当的回调(“完成”或“失败”,然后“始终”)。在jQuery中使用它们可以使代码更具可读性,并允许一些其他技巧(例如,在触发ajax请求之后轻松添加第二个回调)。
bfavaretto 2012年

两者都是异步回调
Raynos

1

延迟回调(又名Promices)使您可以编写顺序异步代码,而不会感到痛苦和回调意大利面条:

$.when( doAjax(), doAnotherAjax() ).then( haveFunWithMoreAjax ).then( animateStuff );

“何时”可让您等待函数并行返回,并且then可以顺序链接。

一个注意事项:jQuery延迟!= Promices / A,它们的语法有些不同。

关于这个话题有很多好文章:一个在IEBlog上,另一个在一些随机博客中,一本书和一个流行的stackoverflow问题


1
恩..结果-OP问了一点不同的事情..好吧,希望这个答案有一天能对别人有所帮助。
c69 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.