promiseを使用し、Node.jsコールバックベースの関数で待機する方法

Node.js APIのほとんどは、promiseがまだ問題にならない時代に構築されており、コールバックベースのソリューションを使用しています。

典型的なNode.jsAPIは次のように機能します。

doSomething(param, (err, result) => {

})

これはライブラリにも当てはまります。一例はnode-redis、そしてプロジェクトで作業しているときに、相互にネストされたコールバックのレベルが多すぎるため、ある時点ですべてのコールバックを削除する必要がありました。これは完璧な「コールバック地獄」シナリオです。

また、関数呼び出しの結果を関数から返す必要があるため、コールバックを回避することが絶対に必要な場合もあります。それがコールバックで返された場合、結果を返す唯一の方法は、関数を使用して結果を送り返すことであり、コールバックパーティは続行します。

const myFunction = () => {
  doSomething(param, (err, result) => {
    return result //can't return this from `myFunction`
  })
}
const myFunction = callback => {
  doSomething(param, (err, result) => {
    callback(result) //no
  })
}

myFunction(result => { console.log(result) })

簡単な解決策があります。

Node.js自体が提供するソリューション。

インポートすることで、promise(および結果としてasync / await構文)をサポートしない関数を「promisify」できます。promisifyコアNode.jsからutilモジュール:

const { promisify } = require('util')

次に、それを使用して新しい関数を作成します。

const ahget = promisify(client.hget).bind(client)
const asmembers = promisify(client.smembers).bind(client)
const ahkeys = promisify(client.hkeys).bind(client)

追加した方法をご覧くださいa意味する手紙非同期

これで、この例の「コールバック地獄」を変更できます。

client.hget(`user:${req.session.userid}`, 'username', (err, currentUserName) => {
  client.smembers(`followers:${currentUserName}`, (err, followers) => {
    client.hkeys('users', (err, users) => {
      res.render('dashboard', {
        users: users.filter((user) => user !== currentUserName && followers.indexOf(user) === -1)
      })
    })
  })
})

はるかにきれいに:

const currentUserName = await ahget(`user:${req.session.userid}`, 'username')
const followers = await asmembers(`followers:${currentUserName}`)    
const users = await ahkeys('users')

res.render(‘dashboard’, { users: users.filter((user) => user !== currentUserName && followers.indexOf(user) === -1) })

これは、サードパーティのライブラリを使用している場合のように、アクセスできない関数を使用する場合に最適です。

内部的には、promisifyは関数をpromiseでラップし、それを返します。

これを手動で行うこともできます。関数からpromiseを返し、それをasync / awaitで使用します。

const handleLogin = (req, user) => {
  return new Promise((resolve, reject) => {
    req.login(user, (err) => {
      if (err) {
        return reject({
          error: true,
          message: err,
        })
      }
      return resolve({
        success: true,
      })
    })
  })
}

//… const resultLogin = await handleLogin(req, user)

私の無料ダウンロードNode.jsハンドブック


その他のノードチュートリアル: