遅延コールバックとは何ですか?


15

関数を別の関数に渡し、その関数が提供された関数を自由に使用するコールバックのアイデアを理解しています。

グーグルした後でも、遅延コールバックを理解するのに苦労しています。

誰か簡単な説明をお願いできますか?私はRubyでプログラミングしますが、C / C ++も少し知っていますが、何よりも私は経験豊富なアセンブリ言語プログラマーでした。だから私はそれがポップされるコールバックアドレスのスタックに少し似ているのだろうか?私はjqueryまたはnode.jsを学びたいと思っており、これらの遅延コールバックは両方に不可欠のようです。基本的なスレッドの原理を理解しています(ただし、mutexオブジェクトは頭を痛めます;)


jQueryのDeferredオブジェクトを意味しますか?これはNode.jsに固有のものですか?
-bfavaretto

1
いいえ、一般的には意味がありません。私はjqueryとおそらくnode.jsを学びたいと思っていますが、実際に遅延コールバックが実際に何であるかを把握する必要があると感じました。コールバックに関するWikipediaの記事を読みましたが、遅延コールバックを理解することができませんでした。これは、それを使用するこれらの言語に関係する非同期操作のパラダイムに内在するようです。


1
それらの実装とは対照的に、遅延コールバックの概念的なアイデアを本当に求めています-それをより明確にしないと申し訳ありません。私は、人々が答えを提案する方法を知っているように、私が明確化しようとしているアイデアと私のプログラミングの背景を説明するために、言語の例をもっと与えました。これまでの回答に感謝します-私はそこに着いています!
10

わかりました、みなさん、ありがとう!しかし、私は答えをどのように行うのか分かりません。キャメロンは概念を最も簡単に説明し、それが私が本当に望んでいたことでしたが、他の人も私の知識に気づき、追加しました。私はこれに新しいので答えを受け入れる方法がわからない;)
10

回答:


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/をご覧ください。


これはおそらく、遅延コールバックの概念を理解した後は非常に貴重です。申し訳ありませんが、遅延コールバックとは何かという概念はまだ理解できません。その背後にある概念的なアイデアをもっと探しています。ミヒアのアイデアに沿って並べ替えます。頭を一周できたら、jsを理解できるかもしれません。
10

3

確かではありませんが、遅延コールバックは非同期コールバックを指していると思うので、それをグーグルで検索する方が幸運でしょう。

私が見つけた最良の説明はhttp://www.nodebeginner.orgにありました

ちょっと、おそらくExpensiveFunction()、あなたのことをしてください、しかし、私、単一のNode.jsスレッドは、あなたが終わるまでここで待つつもりはありません。ここにこのcallbackFunction()を追加し、高価な作業を終えたら呼び出しますか?ありがとう!」

この例では、ExpensiveFunctionはおそらく非ブロッキング(または非同期関数)です。これは、すぐに実行されるのではなく、いわゆるイベントループに配置されることを意味します。node.jsスレッドは実行を継続しますが、ある時点で、イベントループから何かを実行することを決定します。probablyExpensiveFunctionに到達すると、それを呼び出し、おそらくExpensiveFunctionの実行が終了すると、パラメーターとして渡された(遅延)コールバックを呼び出します。

おそらくExpensiveFunctionの例として、あなたはfs.readFileを取ることができます


ありがとう。しかし、すでに返ってきてメインの実行スレッドに戻っている場合、高価な関数はどうするのでしょうか?私はそのビットを取得しません。関数は終了後も何らかの形で持続すると言っていますか?

答えを編集しました。たぶん今はもっと明確です。

非常に役立ちます。しかし...この保存されたコールバックの配列を処理する必要がありますか?つまり、このリストを処理しているのは何ですか。(たとえば)jsがバックグラウンドでこれらのコールバックを解除するのは何もしなくてもいいのでしょうか、それともイベントによってnode.jsなどが特定のコールバックを呼び出すのですか。申し訳ありませんが、私はあなたが言っていることの約70%を
受け取っ

@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で遅延オブジェクトとそれらと対話する複雑なシステムを使用して、メソッドを使用して同じことを実際に行うだけで似たようなことをしますか?
10

1
@tentimes、まさに!コールバックは通常、イベントに応じて実行されます(ただし、「コールバック」はjs言語の構成要素ではないため、この用語は他のコンテキストで使用される場合があります)。Kevinの答えに見られる遅延オブジェクト(約束)は、基本的には構文糖です。何らかの(非同期)イベントがトリガーされると「解決」または「拒否」され、適切なコールバック(「完了」または「失敗」、「常に」)が呼び出されます。これらをjQueryで使用すると、コードが読みやすくなり、いくつかの追加のトリック(たとえば、ajaxリクエストの実行後に簡単に2番目のコールバックを追加するなど)が可能になります。
-bfavaretto

どちらも、非同期コールバックです
レイノス

1

遅延コールバック(別名 Promices)を使用すると、痛みやコールバックスパゲッティなしで、シーケンシャルな非同期コードを記述できます。

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

'when'を使用すると、関数が並列に戻るのを待つthenことができ、順番に連鎖できます。

1つの注:jQueryの遅延!= Promices / A、それらの構文は少し異なります。

トピックに関する良い記事があります:IEBlogにあるもの、ランダムなブログにあるもの、一般的なstackoverflowの質問


1
ええと、判明しました-OPは少し違うことを尋ねました..まあ、この答えがいつか誰かの助けになることを願っています。
c69
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.