例として手先を持つJavaScriptコールバック





コールバック。 非同期。 ノンブロッキング。 正直に言うと、これらのJSの概念はすべて、コードが再び機能しなくなるたびに髪を引き裂かせます。 私も同じような気持ちでした。 この抽象的な考えをより簡単に理解するのに役立つ簡単な類推が必要でした。 もちろん、オンラインで多くの優れたトレーニング資料があります( このような、またはこのような)。 しかし、それらのすべては通常、すぐにかなり複雑なことから始まります。



私はもっ​​と近く、理解できるものが必要でした。



私は手下が必要でした。







これらの面白い生き物を例として、コールバックとは何かを皆に説明します。 私のこの例えで、読者は手先の達人として行動します。 コードで何でもするように注文することができます。 しかし!



  1. 君主は一人しかいない。
  2. ミニオンはあなたから注文を受けるはずです。 彼らは自分で決断することはできません。




(ミニオンの公式の定義は、「誰かが弱く、重要ではなく、強いリーダーまたはボスの命令を満たしている」)



主なアイデア



jQueryまたはJavaScriptで別の関数またはメソッド内に 「関数()」が表示されるたびに、代わりに「ミニオン()」が記述されていると想像してください。 もちろん、JSはこのコマンドを認識しないため、これを書くことはできません(実際の「ミニオン」関数を作成しない限り)。 しかし、コールバックを作成するとき、実際にミニオンに順序を与えます。



ご注文を待っている手先の例:



function myFunction(input, function(err, data){ });
      
      





これは次のように言い換えることができます。



 function myFunction(input, minion(err, data){ });
      
      





ミニオンのない通常の関数の例:



 function addOne(data){ return data++; };
      
      





JQueryの例



基本



例1:



 $('.myButton').click(function(){ $('.secondEl').show(); });
      
      





これは言い換えることができることを思い出してください。

例2:



 $('.myButton').click(minion(){ $('.secondEl').show(); });
      
      





ここでコールバックは何をしていますか?



あなたはマスターであり、ファイル全体、または複数のファイル内で発生するイベントに注意する必要があります。 jQueryのある種の小さなクリックハンドラーで大騒ぎする時間はありません! したがって、例2に示すように、このタスクをミニオンに割り当てます。これは非常に単純な関数であり、おそらく自分で行うこともできます。 そして、それが20行の長さだったら? ユーザーからのその他の指示を受け入れる必要があるため、20行関数に気を取られるべきではありません。 したがって、ユーザーが.myButton



クリックするとすぐに、最初の行からこれを行うようにミニオンに指示します。 これで、他の手先に命令を与えることができます。これは、すべてを自分で行うよりもはるかに効果的であり、重要な機能を自由になるまで待ちます。







アニメーション



ミニオンの重要性を強調するために、表示/非表示のシーケンスを見てみましょう。



 $('button').click(function(){ console.log("One"); $('.firstChild').show(function(){ console.log("Two"); $('.childofChild').show(); }); console.log("Three"); });
      
      





コードを順番に読み、手先をあなたの側に引き付けない場合、「1」、「2」、「3」がコンソールに表示されます。 しかし、ミニオンがいる場合は、「One」、「Three」、「Two」がコンソールに表示されます。 理由は次のとおりです。



 $('button').click(minion(){ console.log("One"); $('.firstChild').show(minion(){ console.log("Two"); $('.childofChild').show(); }); console.log("Three"); });
      
      







ここから非常に重要な教訓を学ぶことができます。コールバックは、さまざまなアクションが実行される順序を決定します。 このツールの威力を想像してください。 連続したコマンドから1つの長い行を作成する必要とは対照的に、イベントのシーケンスを正確に設定できます。 コールバックにより、柔軟性が大幅に向上します。 あなたの命令を果たすために手下を得ることができなかったなら、あなたはあなた自身ですべてをしなければなりません。



実際、前述のjQueryロジックはcallbacksでのみ機能します 。 たとえば、行では、親div



表示された後に子div



が表示される必要div



ます。 親が非表示の場合、子を表示できません 。 また、コールバックは、子div



が親div



後に表示されるようにする唯一の方法です。



上記の例にコールバックがない場合、3行目のshow()



メソッドがまだ実行されていないため、5行目がエラーの原因になります。 1行目で起動された最初のミニオンは、4行目と5行目が実行されるときにタスクを2番目のミニオンに渡します。最初のshow()



後、2番目のミニオンが2番目のshow()



を開始および完了show()



ます。 それまでに、最初のミニオンは、前の操作が完了するのを待たずに、外部機能の残りの部分に移動します。







Vanilla JavaScript / Node.jsの例



パラメータとコールバックを使用する



 //   (generic) reportOrders      function reportOrders (minionOrders) { if ( typeof minionOrders === "string"){ console.log(minionOrders); } else if ( typeof minionOrders === "object"){ for (var item in minionOrders) { console.log(item + ": " + minionOrders[item]); } } } //    ,    —  function speakOrders (orders, callback) { callback (orders); } //     speakOrders,   reportOrders   . //   reportOrders     ( )   speakOrders speakOrders ({name:"Minion1031", speciality:"Scribe"}, reportOrders); // Console // name: Minion1031 // speciality: Scribe
      
      





より複雑な例! 2行目と14行目は単なる関数宣言なので、全体の動きが始まる20行目に進みましょう。 2つのパラメーターを指定してspeakOrders関数を呼び出します。 最初のパラメーターは、ミニオンからレポートを受け取りたい状態を持つオブジェクトです。 2番目のパラメーターは、 reportOrders



というコールバックreportOrders







ミニオンは、そのような順序を与えるまでreportOrders



実行できません。 これがまさにこの機能の実行方法です。 20行目の指示でspeakOrders



を呼び出しますspeakOrders



行目に進み、関数speakOrders



の機能を見てみましょう。 明らかに、彼女はコールバックに指示を渡します。



20行目では、 reportOrders



関数reportOrders



コールバックとして宣言されていますが、誰でも使用できます。 memorizeOrders



tellMySpouse



、関数に任意の名前を付けることができます。 14行目の関数宣言で「コールバック」という単語を使用することは、他の人がコードを見て何が何であるかを理解できるように、適切な形式と見なされます。 しかし、あなたは他の言葉を使うことができます! 縮小した例を次に示します。



 //   (generic) reportOrders      function reportOrders (minionOrders) { if ( typeof minionOrders === "string"){ console.log(minionOrders); } else if ( typeof minionOrders === "object"){ for (var item in minionOrders) { console.log(item + ": " + minionOrders[item]); } } } //    ,    —  function speakOrders (orders, minion>) { minion(orders); } //     speakOrders,   reportOrders   . //   reportOrders     ( )   speakOrders the speakOrders function speakOrders ({name:"Minion1031", speciality:"Scribe"}, reportOrders); // Console // name: Minion1031 // speciality: Scribe
      
      





14〜15行の両方に、「コールバック」に代わるミニオンが1つだけあります。



20行目speakOrders



呼び出しspeakOrders



。 名前付きオブジェクトと目的を渡しましょう。 2番目のパラメーターは、文字列、関数など、何でもかまいません。



14-15行目:2番目のパラメーターがコールバックである必要があることを定義します。これはミニオン()です。 speakOrders



関数を呼び出すたびに、2番目のパラメーターが関数speakOrders



ことがわかります。 この例では、 reportOrders



です。



15行目 :20行目から、ミニオンがreportOrders



関数を処理する必要があることがreportOrders



ます。 彼は注文のパラメーター、つまりオブジェクトを受け取ります。 レポートを正常に作成するには、これらの指示が必要です。



2行目 :15行目の順序変数は、関数内でminionOrders



として参照されるようにminionOrders



reportOrders



関数が完了し、名前と宛先が返されます。



ここで、コールバックは、オブジェクトがたどるべきパスを明確に追跡する上で重要な役割を果たします。 それらがなければ、コードはモノリシックで厳密に順序付けられたヒープになり、関数の再利用や実行順序の変更に関して柔軟性がなくなります。







Node.js



Expressquery moduleを使用する次の例を見てください。 これまでのところ、これは最も難しいです!



 var request = require('request'); var app = require('express')(); var results; function logRes(){ console.log(results); } app.get('/storeData', function(req,res){ readResult(logRes) }); function readResult(callback){ request('http://someroute.com/api', function(err, response, body){ results=body; callback(); }); }
      
      





ユーザーが単純にroute /storeData



沿ってGETリクエストを送信したと想像して/storeData



。 9行目から始めましょう。この例では、コールバックを使用するための前述のオプションがすべて使用されます。



  1. 9行目で、このメソッドはjQueryのクリックハンドラーの例で説明したものと同様のコールバックを使用します。
  2. 行14は、リクエストに関連付けられた非同期実行を偽のAPIに適用します。 これはjQueryアニメーションの例です。
  3. 最後に、13行目では、バニラJSの例に似たコールバックパラメーターを宣言しています。


誤解を避けるため、ここでは、ミニオンに実行順序に従って番号が割り当てられるミニオン化された例を示します。



 var request = require('request'); var app = require('express')(); var results; function logRes(){ console.log(results); } app.get('/storeData', minion1>(req,res){ readResult(logRes) }); function readResult(minion3){ request('http://someroute.com/api', minion2(err, response, body){ results=body; minion3(); }); }
      
      









では、3番目のミニオンは2番目の後にどのように呼び出されましたか?



最初に戻ると、最初の例に戻ると、13行目にコールバックの初期化が表示されます。これは、 readResult()



関数の呼び出しにはreadResult()



コールバックパラメーターが必要であることを意味します。 このコールバックは後で16行目に適用され、14行目のAPIリクエストの結果を使用します。これは、リクエスト自体にコールバックがあるためです!



コールバック(3番目のミニオン)が要求の範囲外で17行目より下にあると想像してください。 この場合、リクエストが完了するまで実行されるため、2番目のミニオンになります。 さらに、要求に対する応答は受信されなかったため、機能全体が無意味になります。 一番下の行は、最初に要求を完了してから応答を渡すことです。



繰り返しますが、2つの別個のリクエストのreadResult()



関数を使用すると、リクエストの完了後に3番目のミニオンが確実に動作を開始します。 コールバックを使用すると、この特定の順序を指定できます。



おわりに



あなたはあなたの欲望を果たす準備ができて、あなたの指揮下で、小さな召使をきしむの大群である、手下の主です。 あなたが彼らに正しい指示を与えることができれば、彼らはあなたの人生を大いに促進し、あなたにとって最も難しいことをすべてすることができます。



All Articles