web-dev-qa-db-ja.com

thenとcatchの約束の連鎖

Bluebird Promiseライブラリを使用しています。約束を連鎖させ、特定の約束エラーをキャッチしたいと思います。ここに私がやっていることがあります:

getSession(sessionId)
  .catch(function (err) {
    next(new Error('session not found'));
  })
  .then(function (session) {
    return getUser(session.user_id);
  })
  .catch(function (err) {
    next(new Error('user not found'));
  })
  .then(function (user) {
    req.user = user;
    next();
  });

ただし、getSessionによってエラーがスローされた場合、2つのcatchと2番目のthenが呼び出されます。最初のcatchでエラーの伝播を停止したいので、2番目のcatchgetUserがスローされたときにのみ呼び出され、2番目のthengetUserが成功したとき。どうする?

25

.catchメソッドによって返されるpromiseは、コールバックの結果で解決されます。チェーンの伝播を停止するだけではありません。チェーンを分岐する必要があります。

var session = getSession(sessionId);
session.catch(function (err) { next(new Error('session not found')); });
var user = session.get("user_id").then(getUser);
user.catch(function (err) { next(new Error('user not found')); })
user.then(function (user) {
    req.user = user;
    next();
});

または、thenへの2番目のコールバックを使用します。

getSession(sessionId).then(function(session) {
    getUser(session.user_id).then(function (user) {
        req.user = user;
        next();
    }, function (err) {
        next(new Error('user not found'));
    });
}, function (err) {
    next(new Error('session not found'));
});

あるいは、エラーをチェーン全体に伝播し、最後にのみnextを呼び出すほうが良い方法です。

getSession(sessionId).catch(function (err) {
    throw new Error('session not found'));
}).then(function(session) {
    return getUser(session.user_id).catch(function (err) {
        throw new Error('user not found'));
    })
}).then(function (user) {
    req.user = user;
    return null;
}).then(next, next);
22
Bergi

Promiseにbluebirdを使用しているため、実際にはすべての関数の後にcatchステートメントは必要ありません。すべてのthenを連結して、1回のキャッチですべてを閉じることができます。このようなもの:

getSession(sessionId)
  .then(function (session) {
    return getUser(session.user_id);
  })
  .then(function (user) {
    req.user = user;
    next();
  })
  .catch(function(error){
    /* potentially some code for generating an error specific message here */
    next(error);
  });

エラーメッセージがエラーの内容を伝えていると仮定すると、「セッションが見つかりません」や「ユーザーが見つかりません」などのエラー固有のメッセージを送信することは可能ですが、エラーメッセージを調べてその内容を確認する必要があります君は。

注:エラーがあるかどうかに関係なく、おそらくnextを呼び出す理由があると確信していますが、エラーが発生した場合はconsole.error(error)をスローすると便利です。または、console.error、res.send(404)、または同様のもののいずれかに関係なく、他のエラー処理関数を使用できます。

7
Mercury

私はそれをそのように使用しています:

getSession(x)
.then(function (a) {
    ...
})
.then(function (b) {
    if(err){
        throw next(new Error('err msg'))
    }
    ...
})
.then(function (c) {
    ...
})
.catch(next);
1
Burak Dalkıran