web-dev-qa-db-ja.com

なぜ「コールバック関数」が必要なのですか?

私は本を​​読んでいますprogramming in Lua。それは言った

クロージャーは、多くの状況で貴重なツールを提供します。これまで見てきたように、これらはsortなどの高次関数の引数として役立ちます。クロージャーは、newCounterの例のように、他の関数を作成する関数にも役立ちます。このメカニズムにより、Luaプログラムは、関数型の世界からの高度なプログラミング手法を組み込むことができます。クロージャーは、コールバック関数にも役立ちます。ここでの典型的な例は、従来のGUIツールキットでボタンを作成するときに発生します。各ボタンには、ユーザーがボタンを押したときに呼び出されるコールバック関数があります。異なるボタンを押すと、異なるボタンが少し異なる動作をするようにします。たとえば、デジタル計算機には、各桁に1つずつ、計10個の同様のボタンが必要です。次のような関数を使用して、それぞれを作成できます。

function digitButton (digit)
  return Button{label = tostring(digit),
                action = function ()
                  add_to_display(digit)
                  end}
end

digitButtonを呼び出すと、actionが返されるようです(これによりクロージャが作成されます)。したがって、digitに渡されたdigitButtonにアクセスできます。 ] _。

私の質問はそれです:

Why we need call back functions? what situations can I apply this to?

この例では、Buttonは新しいボタンを作成するツールキット関数であると想定しています。 labelはボタンのラベルです。アクションは、ボタンが押されたときに呼び出されるコールバッククロージャです。コールバックは、digitButtonがタスクを実行した後、ローカル変数digitがスコープ外になった後も長時間呼び出すことができますが、この変数には引き続きアクセスできます。

著者によると、同様の例は次のようになると思います:

function Button(t)
  -- maybe you should set the button here
  return t.action -- so that you can call this later
end

function add_to_display(digit)
  print ("Display the button label: " .. tostring(digit))
end

function digitButton(digit)
  return Button{label = tostring(digit),
                action = function ()
                           add_to_display(digit)
                           end}
end

click_action = digitButton(10)
click_action()

したがって、the callback can be called a long time after digitButton did its task and after the local variable digit went out of scope.

16
Lucas Li

ガイ1からガイ2:ユーザーがそこをクリックしたときに何かしたいのですが、問題が発生したら電話をかけ直しますか?

ユーザーがここをクリックすると、ガイ2はガイ1にコールバックします。

45

いいえ、それは決してreturnアクションではありません。ボタンは、ユーザーがクリックするとexecuteになります。それが答えです。制御しないイベントに反応して別のコンポーネントで発生するアクションを定義する場合は、コールバック関数が必要です(システムの一部であるイベントループは、ボタンのメソッドを実行し、ボタンのメソッドを実行します)アクション)。

21
Jan Hudec

コールバックの使用のより良い例は非同期関数にあると思います。 Luaについて話すことはできませんが、JavaScriptで最も一般的な非同期アクションの1つは、AJAXを介してサーバーに接続することです。

AJAX呼び出しは非同期です。つまり、次のようなことをすると:

_var ajax = ajaxCall();
if(ajax == true) {
  // Do something
}
_

ifブロックの内容は正しく確実に実行されません。実行された場合、それは、実行がifステートメントに到達する前にajaxCall()関数がたまたま終了したためです。

ただし、コールバックは、必要な関数を呼び出す前に非同期呼び出しが確実に終了することにより、この問題を排除します。したがって、コードは次のように変更されます。

_function ajaxCallback(response) {   
  if(response == true) {
    // Do something   
  }
}

ajaxCall(ajaxCallback);
_

これの目的は、インターフェースの描画など、他のことに干渉することなく、データの収集などを実行できるようにすることです。データ収集が同期的である場合、アプリケーションがデータを取得するのを待っているため、インターフェースが応答しなくなります。ほとんどのユーザーはアプリケーションが「クラッシュした」と考え、プロセスを終了しようとするため、応答しないインターフェースはユーザーエクスペリエンスにとって非常に悪いものです。

この動作を確認するには、ページ全体を再読み込みせずに、あらゆる種類の更新を行うWebサイトを確認するだけです。 Twitter、LinkedIn、StackExchangeサイトがその良い例です。フィードのTwitterの「エンドレススクロール」とSEの通知(ユーザー通知と、質問に新しいアクティビティがあることの通知の両方)は、非同期呼び出しによって提供されます。スピナーがどこかにある場合、それはそのセクションが非同期呼び出しを行い、その呼び出しが終了するのを待っていることを意味しますが、インターフェース上の他のものと対話することができます(他の非同期呼び出しを行うこともできます)。その呼び出しが完了すると、それに応じてインターフェイスが反応し、更新されます。

16
Shauna

あなたが質問した

なぜ「コールバック関数」が必要なのですか?

私は簡潔で明確な方法で回答するように努めます(もし失敗した場合は、この回答の下部にあるwikiリンクを参照してください)。

コールバックは、何かの特定の実装を可能な限り最後まで延期するために使用されます。

ボタンの例は、これをよく表しています。アプリケーションに、ページをプリンタに印刷するボタンが必要だとすると、これを行うために新しいPrinterButtonクラス全体をコーディングする必要がある世界を想像できます。

幸いにも、コールバックの概念(継承と テンプレートパターン の使用も一種のコールバックセマンティックです)があるため、その必要はありません。

ボタンのすべての側面を再実装する代わりに、ボタンの実装に追加することです。 Buttonには、押されたときに何かを実行するという概念があります。それが何であるかを伝えるだけです。

フレームワークに動作を注入するこのメカニズムは、コールバックと呼ばれます。

例:

HTMLボタンにいくつかの動作を注入しましょう:

_<button onclick="print()">Print page through a callback to the print() method</button>
_

このインスタンスでは、onclickはコールバックを指します。この例では、print()メソッドです。


http://en.wikipedia.org/wiki/Callback_(computer_programming)

12
AlexanderBrevig

なぜコールバック関数が必要なのですか?これをどのような状況に適用できますか?

コールバック関数は、イベント駆動型プログラミングで非常に役立ちます。イベントによって正しいコードがトリガーされるようにプログラムを設定できます。これは、ユーザーがUIの任意の要素(ボタンやメニュー項目など)をクリックできるGUIを備えたプログラムでは非常に一般的であり、適切なコードが実行されます。

コールバックなしで何が起こるか:

男1:わかりました、そのようなことが起こるのを待っています。 (ホイッスル、親指をいじる)

男2:くそっ! Guy 1が表示されないのはなぜですか?何が起こっているのか見たい!私のものはどこにあります?この辺りで何をするつもりなのでしょうか?

2
Jim

これに遭遇し、より最新の答えを提供したかった...

コールバック関数を使用すると、後での時点でデータを処理して、残りのコードを待機せずに実行できます。非同期コードを使用すると、後でを実行するという贅沢が可能になります。私が遭遇したコールバック関数の最も読みやすい例は、JavaScriptのPromiseです。以下の例では、function(result)または(newResult)または(finalResult)が表示されるたびに、これらはコールバック関数です。中括弧内のコードは、データがサーバーから返されると実行されます。この時点でのみ、これらの関数を実行しても意味がありません。必要なデータが利用可能になったためです。

doSomething().then(function(result) {
  return doSomethingElse(result);
})
.then(function(newResult) {
  return doThirdThing(newResult);
})
.then(function(finalResult) {
  console.log('Got the final result: ' + finalResult);
})
.catch(failureCallback);

コードは...から取得されます https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises

うまくいけば、これは誰かを助けます。これがコールバックを理解するのに役立ちました:)

1
NRV

まず、コールバックという用語は、何かに使用されているクロージャーを指します。

たとえば、クロージャ関数を作成し、それを変数に格納するとします。それは何にも使用されていないため、コールバックではありません。

ただし、クロージャを作成して、何かが発生したときに呼び出される場所に格納するとします。現在はコールバックと呼ばれています。

通常、コールバックは、コールバックを呼び出す部分とは異なるプログラムの部分によって作成されます。したがって、プログラムの一部が他の部分を「コールバック」していると想像するのは簡単です。

簡単に言えば、コールバックを使用すると、プログラムの一部で、何かが発生したときに別の部分に何か(何か)を実行するように指示できます。

クロージャーで使用されているために変数が存続することに関しては、それはupvaluesと呼ばれる完全に異なる機能です(別名、Luaを話さない人の間で「ローカル変数の寿命を延ばす」)。そして、それも非常に便利です。

1
Jonathan Graef

コールバックは、少なくともFortranの初期の頃から存在しています。たとえば、ルンゲクッタソルバーなどのODE(常微分方程式)ソルバーがある場合、次のようになります。

subroutine rungekutta(neq, t, tend, y, deriv)
  integer neq             ! number of differential equations
  double precision t      ! initial time
  double precision tend   ! final time
  double precision y(neq) ! state vector
  ! deriv is the callback function to evaluate the state derivative
  ...
  deriv(neq, t, y, yprime) ! call deriv to get the state derivative
  ...
  deriv(neq, t, y, yprime) ! call it several times
  ...
end subroutine

これにより、呼び出し元は、必要に応じて呼び出される専用の関数を渡すことで、サブルーチンの動作をカスタマイズできます。これにより、ODEソルバーを使用してさまざまなシステムをシミュレーションできます。

1
Mike Dunlavey