0

ノード アプリで関数を実行していますが、非同期コードを適切に記述する方法を理解していないために機能しません。以下は、メールでプロファイルを取り込む関数です。各メールをループして、そのユーザーがデータベースに存在するかどうかを確認したいと思います。もしそうなら、与えられたコールバックを返し、他に何もせずに関数を完全に存在させたいと思います。ユーザーが見つからない場合は、プロファイルで指定された情報に基づいて新しいユーザーを作成し、新しく作成されたユーザーと同じコールバックを返します。現在、データベースでユーザーが既に見つかっている場合でも新しいユーザーを作成することを除いて、関数は意図したとおりに機能します。(「ユーザー」変数は上記で定義されており、「作成」機能があります。また、「非同期」の使用を避けたいと思います

function processProfile(profile, callback) {
        var existingUser;
        if (profile.emails) {
            profile.emails.forEach(function(email) {
                console.log("Searching for user with this email:" + email.value);
                existingUser = findUserByEmail(email.value);
                if (existingUser) {
                    console.log("Found the existing user");
                    return callback(null, existingUser);
                }
            });
            if(!existingUser){
                console.log("Creating new user");
                var newUser = {
                    id: profile.id,
                    firstName: profile.name.givenName,
                    lastName: profile.name.familyName,
                    email: profile.emails[0].value
                };
                user.create(newUser, profile.provider, function(err, user) {
                    if (err) throw err;
                    return callback(null, user);
                });
            }
        }
    }
4

1 に答える 1

1

これに何か問題がありますか?

function processProfile(profile, callback) {
    var existingUser;
    var index = 0;

    function processNextEmail() {
        if(index >= profile.emails.size()) return; //When we've popped nothing exit
        var email = profile.emails[index++];
        console.log("Searching for user with this email:" + email.value);
        existingUser = findUserByEmail(email.value);
        if (existingUser) {
            console.log("Found the existing user");
            callback(null, existingUser);
            processEmail();//recursive call to prcess the next email
        } else {
            console.log("Creating new user");
        var newUser = {
            id: profile.id,
            firstName: profile.name.givenName,
            lastName: profile.name.familyName,
            email: profile.emails[0].value
        };
        user.create(newUser, provider, function(err, user) {
            if (err) throw err;
            callback(null, user);
            processNextEmail();//recursive call to process the next email after creating the user and adding it to the database.
        });
        }
    }

    processNextEmail();
}

電子メールを削除しないように再帰的なロジックが必要な場合は、processProfile() クロージャーのスコープ内でインデックスを含む簡単な変更を行うことができます。

また、return callback() 行は実際には何もしないことに注意してください。非同期に発生している関数から戻るのは時間の無駄です。コールバックを呼び出すだけで、必要に応じて空のリターンを呼び出して関数の残りをスキップできますが、リターンがロジックの流れに影響しない限り、これは不要です。

編集:これは、例が単純すぎてもっと面白くないことがわかりました。以下のコードは、非同期コードを理解するのに苦労している職場の一部の人々の例として使用しました。ノードで同期コードを使用しても問題ないと思うのは、構成データを収集するためです。構成がファイルに保存されていると仮定して、そのファイルからファイル名を取得し、別のファイルから構成データの別のレイヤーを収集します。これは、readFileSyn を使用するか、readFile を使用する 2 つの方法で実行できます。2 番目のファイルがどこに保存されているかを知るために、最初のファイルからファイル名を取得する必要があるため、最初のステップが完了するのを待つ必要があるため、非同期バージョンは注意が必要です。以下は、同期ソリューションと非同期ソリューションの両方のコードです。

//The synchronous way
function useConfigurationData(configData) {
    dosomethinginterestingwith(configData);
}

function getConfigurationData(fileName) {
    var fileName2 = fs.readFileSync(fileName);
    var configurationData = fs.readFileSync(fileName2);
    return configurationData;
}

var fileData = getConfigurationData('someFile');
useConfigurationData(fileData);


//The equivalent async way
function getConfigurationData(fileName, useConfigDataCallBack) {
    fs.readFile(fileName, getConfigDataStepTwo);

    function getConfigDataStepTwo(err, fileName2) {
        fs.readFile(fileName2, getConfigDataStepThree);
    }

    function getConfigDataStepThree(err, fileData) {
        useConfigDataCallBack(fileData);
    }
}

getConfigurationData('someFile', useConfigurationData);

getConfigurationData に提供するコールバックが最後のステップであることに注意してください。グローバルに定義された getConfigurationData 関数に頼ることもできますが、それをコールバックとして渡す方が適切です。

この構文で私が気に入っているのは、2 番目の getConfigurationData 関数内のコードが順番に、非常に同期的に読み取られることです。しかし、ロジックの流れに従うと、すべて非同期で実行されます。読みやすく、ノードの非同期 I/O モデルに従います。構成データの場合、同期オプションは受け入れられると思いますが、これは非同期コールバックから同期動作と構文 (っぽい) を取得する方法の良いデモです。

于 2013-06-27T16:46:19.853 に答える