2017-12-02 8 views
-1

私はasync/awaitを順番にイベントを起動させようとしていますが、console.logのマーカーが私が望んでいた順序と逆の方向にトリガしているので、何かが見当たりません。ノードのネストされた関数で非同期/待機しますか?

users.jsでネストされた関数を使用していますが、async/awaitの複数のバリエーションを試してみましたが、一貫して期待通りに機能しません。

// index.js

var users = require("./users.js"); 

app.post("/getToken", async function(req, res) { 
    if (req.body.email && req.body.password) { 
     const email = req.body.email; 
     const password = req.body.password; 
     const user = await users(email, password) 
     // running this should output console.log("No 1") 
     // from users.js first, but doesn't ? 

     console.log('No 2') 
     if (user) { 
      var payload = { 
       id: user.id 
      }; 
      var token = jwt.encode(payload, cfg.jwtSecret); 
      res.json({ 
       token: token 
      }); 
     } else { 
      res.sendStatus(401); 
     } 
    } else { 
     res.sendStatus(401); 
    } 
}); 

// users.js

module.exports = function(emailAddress, password) { 
    db.connect(); 
    var query = ` 
     SELECT 
      id, 
      email, 
      password, 
      salt 
     FROM 
      users 
     WHERE 
      email = ?`; 
    var query_params = [emailAddress]; 

    db.query(
     query, 
     query_params, 
     function(error, result, fields) { 
      console.log('No 1') 

      if (error) throw error; 
      if (result.length == 1) { 
       if (checkPass(password, result[0].password, result[0].salt)) { 
        return { id: result[0].id } 

       } else { 
        console.log("login False | Password"); 
        return false; 
       } 

      } else { 
       console.log("login False | username"); 
       return false; 
      } 
     } 
    ) 
} 
+0

があなたのdownvoteを説明

はコメントを参照してください?必要に応じて質問に追加して嬉しいです – denden

答えて

3

users.js関数は何も返しません。 queryをコールバックするコールバックは行いますが、全体的な機能はありません。明示的に何も返さないので、それを呼び出す結果はundefinedです。 awaitundefinedの場合はawait Promise.resolve(undefined)のようになり、解像度ハンドラが非常に迅速に呼び出されます。

この関数は、作業が完了するまで解決されない約束を返すようにします。それが古いスタイルのノードcallbck APIなので、new Promiseを使用してその約束を作成することが妥当です(代わりに、そのDBへの約束可能なAPIを取得または作成する)。

私はまた、通常、それは非同期動作されるため、あなたは間違ってconnectを呼んでいる疑いがあるが、それは、同期であるかのようにあなたはそれを処理しています。そして、それを使用して

users.js

module.exports = function(emailAddress, password) { 
    return new Promise((resolve, reject) => { 
     // Use the callback to know when the connection is established 
     db.connect(error => { 
      if (error) { 
       // Connection failed 
       reject(error); 
       return; 
      } 
      var query = ` 
       SELECT 
        id, 
        email, 
        password, 
        salt 
       FROM 
        users 
       WHERE 
        email = ?`; 
      var query_params = [emailAddress]; 
      db.query(
       query, 
       query_params, 
       function(error, result, fields) { 
        // Throwing an error here does nothing useful. Instead, 
        // reject the promise. 
        if (error) { 
         reject(error); 
         return; 
        } 
        // Resolve our promise based on what we got 
        if (result.length == 1) { 
         if (checkPass(password, result[0].password, result[0].salt)) { 
          resolve({ id: result[0].id }); 
         } else { 
          console.log("login False | Password"); 
          resolve(false); 
         } 
        } else { 
         console.log("login False | username"); 
         resolve(false); 
        } 
       } 
      ); 
     }); 
    }); 
} 

:あなたが喜ばことができるかどう

app.post("/getToken", async function(req, res) { 
    // You must handle errors, since `post` won't do anything with the return 
    // value of this function 
    try { 
     if (req.body.email && req.body.password) { 
      const email = req.body.email; 
      const password = req.body.password; 
      // Now this waits here, since `users` returns a promise that 
      // isn't resolved until the query completes 
      const user = await users(email, password) 
      console.log('No 2') 
      if (user) { 
       var payload = { 
        id: user.id 
       }; 
       var token = jwt.encode(payload, cfg.jwtSecret); 
       res.json({ 
        token: token 
       }); 
      } else { 
       res.sendStatus(401); 
      } 
     } else { 
      res.sendStatus(401); 
     } 
    } catch (e) { 
     res.sendStatus(401); 
    } 
}); 
+0

こんにちはT.J.このオプションは、最初のリクエストでのみ動作するように見えますが、2番目のリクエストでは動作しません。表示されるエラーメッセージに基づいて、DB接続に関連する約束の1つが解決されません。 UnhandledPromiseRejectionWarning:未処理の約束拒否(拒否ID:2):エラー:quitを呼び出した後にハンドシェークをエンキューできません。エラー:/ db35.png(エラー:> {{}})エラー*/ (ノード:29523) (node:29523)[DEP0018] DeprecationWarning:未処理の約束拒否は推奨されていません。将来的には、処理されない約束の拒否はNode.jsプロセスをゼロ以外の終了コードで終了させるでしょう。 " – denden

+0

@denden:答えのコードに未定の約束はないので、本当にそれを正しく適用しました。しかし、拒否が処理されていないという事実は、他の問題とは別のものです。明らかに、DBを正しく使用していないということです。それは問題の範囲外ですが、あなたがペアで接続するか、何かを切断する必要があるなら、私は驚くことはありません。 –

+0

よろしくお願いします。 – denden

3

問題はdb.query機能が非同期であるということです - あなたは、データベースの呼び出しが終了したときに実行されるコールバック関数を提供しています。おそらく約束でこの全体の機能をラップする必要があります。

module.exports = function(emailAddress, password) { 
    return new Promise(function(resolve, reject) { 
    db.connect(); 
     var query = ` 
      SELECT 
       id, 
       email, 
       password, 
       salt 
      FROM 
       users 
      WHERE 
       email = ?`; 
     var query_params = [emailAddress]; 

     db.query(
      query, 
      query_params, 
      function(error, result, fields) { 

       if (error) return reject(error) 

       if (result.length == 1) { 
        if (checkPass(password, result[0].password, result[0].salt)) { 
         resolve({id: result[0].id}) 

        } else { 
         console.log("login False | Password"); 
         reject(); 
        } 

       } else { 
        console.log("login False | username"); 
        reject(); 
       } 
      } 
    ) 
    }) 
} 

編集

hereプロミスAPIについての詳細を学ぶことができます。だから、あなたはさらに connect同期を行う必要があります

。ここで私があなたのためにリファクタリングしたコードがあります。それはうまくいくはずです。私はそれをより読みやすくするためにいくつかのES6要素を使用しました。

const connect =() => new Promise((resolve, reject) => { 
    db.connect((err) => { 
     if (err) return reject(err); 

     resolve(); 
    }) 
    }) 

const makeDbRequest = (emailAddress, password) => new Promise((resolve, reject) => { 
    const query = ` 
     SELECT 
      id, 
      email, 
      password, 
      salt 
     FROM 
      users 
     WHERE 
      email = ?`; 

    const query_params = [emailAddress]; 

    db.query(
     query, 
     query_params, 
     handleDbData(resolve, reject, password), 
    ); 
    }) 

const handleDbData = (resolve, reject, password) => (error, result, fields) => { 
    if (error) return reject(error) 

    if (result.length == 1) { 
     if (checkPass(password, result[0].password, result[0].salt)) { 
      resolve({id: result[0].id}) 

     } else { 
      console.log("login False | Password"); 
      reject(); 
     } 

    } else { 
     console.log("login False | username"); 
     reject(); 
    } 
} 

module.exports = (emailAddress, password) => new Promise((resolve, reject) => { 
    connect() 
     .then(() => { 
     makeDbRequest(emailAddress, password) 
      .then(resolve) 
      .catch(reject) 
     }) 
     .catch(reject); 
    }) 
+0

OPはその機能で約束を使用する必要がありますが、修正が必要な他にもたくさんのことがあります。 (おそらく、 'db.connect'はおそらく非同期でもあり、' users.js'からこの関数を呼び出す際の問題はありません。) –

+0

おそらくはいです。しかし、これはこの質問の範囲外です。非同期関数を呼び出す同期関数でasync/awaitを使用することです。 –

+0

問題全体に対処することが範囲外であることに私は同意できません。 –

関連する問題