JSのコールバック関数を理解する

4066 ワード

今日はコードを書く時に関数を書きました.NodejsクエリのpgSQLのデータを調べて結果を返す値にしたいです.その結果、この値が取れないことが分かりました.資料を調べてやっとはっと悟りました.これはNodejsの最大の特性です.データの検索操作は比較的に資源を消耗する操作として、待たずに、直接に後のコードを実行しますので、このような状況が現れます.だから、Nodejsには大量のコールバック関数があります.
JSの中核としては、コールバック関数と非同期実行は密接に関連しており、過去の敷居をまたぐ必要があります.
一体何がコールバック関数ですか?実はコールバック関数は複雑ではなく、二つのポイントが分かります.
1.関数はパラメータとして別の関数で呼び出されます.
2.JSは非同期プログラミング言語であり、つまりJSコードの実行順序は上から下までの順番ではない.ほとんどの言語は同期プログラミング言語です.例えば、今は3行目のコードがあります.システムは必ず1行1行目の順に下に実行します.1行目の実行が終わって、2行目を実行して、最後に3行目を実行します.これは無駄話ではないと言いますか?ちょっと待ってください.JSでは、3行のコードがあります.一番前のコードが最初に実行されたのではなく、最後の行の語句が一番先に実行されたかもしれません.一番前の行に並べば最後に実行されたのです.だから、JSは異歩のプログラミング言語だと言います.
下記はnode.jsを例にとって、一例を挙げて、3歩以内に一体何がコールバック関数ですか?
var fs = require("fs");

var c

 

function f(x) {

    console.log(x)

}

 

function writeFile() {

    fs.writeFile('input.txt', '    fs.writeFile        ', function (err) {

        if (!err) {

            console.log("      !")

            c = 1

        }

    });

}

 

c = 0

writeFile()

f(c)
以上のコードは、大域変数c=0を設定して、writeFile関数(つまりファイルinput.txtを書き込む)を実行します.この関数の中には1行c=1があります.関数が実行されたらf()関数を呼び出すと、f()関数は簡単です.
「正常」のロジックに従って、まずc=0を呼び出して、writeFile関数を呼び出します.この関数の中にはc=1があります.最後にf(c)を呼び出します.また、writeFile()を呼び出すのはf(c)の前ですから、c=1という文は必ず実行されます.結果は1をプリントするはずですが、まさか、結果は0です.明らかに私たちはwriteFile関数の中でcに対して新たに値を付けましたが、なぜまだ0ですか?
プログラムがwriteFile()の行に実行されるときは、比較的時間がかかるIO操作ですので、JSはこの操作を元の場所に止めずに関数が実行されるまで待つのではなく、直接に次のコード(f(c)を実行します.この時、c=1というラインのコードは実行されていません.プリントアウトの結果はまだ0です.
この問題を解決するのはまだ難しいです.私達はf(c)を呼び出してもwriteFile関数に入れればいいじゃないですか?これでc=1を保証してからf(c)を呼び出すことができますよね?そうです.こんなに簡単です.
var fs = require("fs");

var c

 

function f(x) {

    console.log(x)

}

 

function writeFile() { 

    fs.writeFile('input.txt', '    fs.writeFile        ', function (err) {

        if (!err) {

            console.log("      !")

            c = 1

            f(c)

        }

    });

}

 

c = 0

writeFile() 
f(c)をwriteFile()に入れたら、c=1は必ず実行されます.そしてf(c)を実行します.言うまでもなく、結果は必ず1と表示されます.しかし、このように変更するのは完璧ではないです.これはf()を「溶接死」ということをwriteFile()にするのに相当します.ここで私が最終的に呼びたい関数はf()ではなく、他の関数がどうなりますか?いくつかの違いを書いてもいいですか?彼らの違いは最後に呼び出された関数だけですか?これはあまりにも愚かなので、今日の主役:キーワードcalbackが登場しました.
var fs = require("fs");

 

function f(x) {

    console.log(x)

}

 

function writeFile(callback) { //   callback,              ,      

    fs.writeFile('input.txt', '    fs.writeFile        ', function (err) {

        if (!err) {

            console.log("      !")

            c = 1

            callback(c) //             f(),           f(c)

        }

    });

}

var c = 0

writeFile(f) //   f        writeFile  
  
改造後のコードには二回のコールバックキーワードが現れました.最初のcalbackはwriteFileのイメージブックに現れて、定義の役割を果たしています.このパラメータは普通の変数ではなく、一つの関数です.つまり、前に述べたポイント1、いわゆる「函数でパラメータ」です.第二のcalbackはc=1の下に現れ、ここで「実行」という形から伝わってくるその関数を表しています.このように、writeFile()関数は実行終了後、どの関数を呼び出したら「生きる」になりますか?writeFile()関数が実行された後は第二の例のようにf()だけではなく、x()y()z()などの他の関数がありますので、writeFile(x)と書くだけでいいです.
上のコードがよく分かりました.あまり深くないので、今から一言の攻略でまとめます.
ほとんどのプログラミング言語では、関数のイメージは常に外部から内向きの関数によってパラメータを伝達しますが、JSでは、イメージパラメータがキーワードの「calback」であれば、完全に反対です.関数体はある操作を完了した後に内向き外部からある外部関数を呼び出すことを表しています.
時には、いくつかの関数の参照リストにまた関数の定義が表示されます.最初は霧のように感じますが、上の内容を知っていれば、直接に関数の呼び出し時にfunctionの書き方を埋め込むのは簡単です.
このような風に書くと、このように成長します.
var fs = require("fs");

 

function writeFile(callback) { 

    fs.writeFile('input.txt', '    fs.writeFile        ', function (err) {

        if (!err) {

            console.log("      !")

            c = 1

            callback(c) 

        }

    });

}

var c = 0

writeFile(function (x) {

    console.log(x)

})
writeFile()関数はそのままで、それを呼び出す時に直接に関数体をイメージリストに埋め込んで、その役割は一つの例に追いつきます.実は、この例では、fs.writeFile関数の後にも匿名のコール関数function(err){}が付いていますが、この関数はファイルの書き込みが完了したら、それを戻します.書き込み中にエラーが発生したら、変数errによって運ばれます.前のマットがあると信じていますが、その意味はもう理解できます.実はこのような書き方はJSでは最も一般的な主流スタイルです.
転載先:https://www.cnblogs.com/wjcoding/p/11302602.html