UnhandledPromiseRejectionWarning:已经调用了回调(Loopback远程方法)

时间:2017-11-16 00:22:57

标签: node.js async-await loopbackjs es6-promise

我收到错误消息

(node:27301) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Callback was already called.

根据我的理解,在等待和拒绝Mozilla描述中拒绝承诺:

  

如果Promise被拒绝,则await表达式抛出被拒绝的值。

我拒绝回复中的错误,就像我的承诺一样:

Airport.nearbyAirports = async (location, cb) => {
  let airports
  try {
    airports = await new Promise((resolve, reject) => {
      Airport.find({
        // code
      }, (err, results) => {
        if (err)
          reject(err) // Reject here
        else
          resolve(results)
      })
    })
  } catch (err) { // Catch here
    cb(err, null)
    return
  }
  if (!airports.empty)
    cb(null, airports)
  }

我的问题是

  1. 为什么它仍然认为我的承诺拒绝未处理?我认为catch语句应该保持这个错误。
  2. 为什么它会考虑我的回调?我的return中有一个catch语句,因此永远不应该调用它们。

4 个答案:

答案 0 :(得分:4)

问题实际上是我的框架(LoopbackJS),而不是我的功能。显然在撰写本文时,不支持使用promises:

https://loopback.io/doc/en/lb3/Using-promises.html#setup

意思是我甚至不能在我的函数中使用await因为远程方法将我的函数包装在其他地方,所以async总是未处理。我最终回到了内部代码的基于Promise的实现:

Airport.nearbyAirports = (location, cb) => {
const settings = Airport.dataSource.settings
const db = DB(settings)
let airports
NAME_OF_QUERY().then((res) => {
  cb(null, res)
}).catch((err) => {
  cb(err, null)
})

答案 1 :(得分:2)

如果Airport.find()引发异常,则执行将跳转至catch阻止,您的Promise将永远不会被解决或拒绝。也许您需要将其包装在自己的try/catch

Airport.nearbyAirports = async (location, cb) => {
  let airports
  try {
    airports = await new Promise((resolve, reject) => {
      try {
        Airport.find({
          // code
        }, (err, results) => {
          if (err)
            reject(err) // Reject here
          else
            resolve(results)
        })
      } catch (err) {
        reject(err) // Reject here too
        cb(err, null)
      }
    })
  } catch (err) { // Catch here
    cb(err, null)
    return
  }
  if (!airports.empty)
    cb(null, airports)
  }

答案 2 :(得分:2)

作为said here,loopback 3通过允许您使用简单的返回来支持此功能。

这:

Entry.findFooById = async (id, cb) => {
  const result = await Entry.findById(id);
  return result;
};

......相当于:

Entry.findFooById = (id, cb) => {
  Entry.findById(id)
    .then(result => cb(null, result))
    .catch(cb);
};

答案 3 :(得分:0)

我们使用Loopback 2.31.0,它还支持对用于远程方法的异步函数的简单返回。如果将断点放在远程方法中的某个位置,然后在调用堆栈中将其跳到上一层,您将看到如何在环回本身(shared-method.js)中实现它:

  // invoke
  try {
    var retval = method.apply(scope, formattedArgs);
    if (retval && typeof retval.then === 'function') {
      return retval.then(
        function(args) {
          if (returns.length === 1) args = [args];
          var result = SharedMethod.toResult(returns, args);
          debug('- %s - promise result %j', sharedMethod.name, result);
          cb(null, result);
        },
        cb // error handler
      );
    }
    return retval;
  } catch (err) {
    debug('error caught during the invocation of %s', this.name);
    return cb(err);
  }
};

它在这里做什么-它调用您的函数,如果它是一个异步函数-它会返回一个诺言(retval.then === 'function'将是true)。在这种情况下,回信是正确的,可以正确处理您的结果。它还会为您执行错误检查,因此您不再需要尝试/捕获代码中的块了。

因此,在您自己的代码中,您只需要像下面这样使用它即可:

Airport.nearbyAirports = async (location) => {
    let airports = await new Promise((resolve, reject) => {
        Airport.find({
            // code
        }, (err, results) => {
            if (err)
                reject(err) // Reject here
            else
                resolve(results)
        })
    });

    if (!airports.empty)
        return airports;
    }
    else  {
        return {}; // not sure what you would like to return here as it wan not handled in your sample...
    }
}

请注意,您完全不需要在这里使用回调(cb)。