Loopback support for async/await
Asked Answered
P

3

7

I'm using loopback 3 to build a REST service, and I want to use the async/await instead of having to use the callbacks. So instead of doing that:

MyModel.myFunction = (callback) => {
  MyModel.find({where: {id: 2}}, (e, data) => {
    if (e) return callback(e);
    callback(null, data);
  });
};

I would greatly prefer to do:

MyModel.myFunction = async (callback) => {
  try {
    const data = await MyModel.find({where: {id: 2}});
    callback(null, data);
  } catch (e) {
    console.error(e);
    callback(e);
  }
};

The callback approach works perfectly - async/await however gives numerous errors:

  • UnhandledPromiseRejectionWarning: Error: Callback was already called.
  • UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch().

What's wrong? I cannot get through this issue.

Porous answered 1/5, 2018 at 20:6 Comment(5)
Do you really want to ignore errors (like in your original code)?Occupant
Do not mix promises with callback style. It doesn't end up well as you can see - you are not correctly handling the case where callback throws.Occupant
Is that your actual code? I copy pasted (and added a curly brace) it into a server.js, just tried it and it throws no errors.Corked
Sure, I want to handle errors in the 1st case. It is the actual code, it throws errors for me, it's in the mymodel.js file (as the additional remote endpoint).Porous
if you are using async function you don't need to use callback, just return the result, just remove callback from the function arguments and instead of calling callback, just return the result.Vaduz
D
11

Some refactoring:

MyModel.myFunction = async () => {
  try {
    const data = await MyModel.find({where: {id: 2}});
    return data; // it's enough as the async means it returns a promise
  } catch (e) {
    console.error(e);
    throw e;
  }
};

This one in case if you don't need to log an error (loopback error handler logs it instead of you):

MyModel.myFunction = async () => {
  return MyModel.find({where: {id: 2}});
};
Deland answered 2/5, 2018 at 7:57 Comment(0)
P
1

Looks like I was simply mixing two concepts, this is the solution:

MyModel.myFunction = async (callback) => {
  try {
    const data = await MyModel.find({where: {id: 2}});
    return Promise.resolve(data);
  } catch (e) {
    console.error(e);
    return Promise.reject(e);
  }
};
Porous answered 1/5, 2018 at 20:28 Comment(1)
Also drop the callback parameter. And you can simplify to return data and to throw e.Occupant
C
0

An easier way would be to just use a function to resolve your promise and just pass the db query to it, like so.

async function ReturnWithResolvedPromise(dbQuery) {
try {
    return Promise.resolve(dbQuery);
} catch (e) {
    return Promise.reject(e);
}}

and then call this like so

let result =    await ReturnWithResolvedPromise(await Users.count({where: {Region: 'UK'}}));
Chadwickchae answered 16/11, 2018 at 11:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.