Using await in then callback - the keyword 'await' is reserved
Asked Answered
B

1

20

In node.js, I have a database transaction, where I want to call an async method in then callback, but I get error message the keyword 'await' is reserved.

This is async saveImage function:

const saveImage = async (parsedLink) => {
  AWS.config.region = config.awsSettings.region;
  AWS.config.accessKeyId = config.awsSettings.accessKeyId;
  AWS.config.secretAccessKey = config.awsSettings.secretAccessKey;
  const bucket = new AWS.S3({
    params: {
      Bucket: config.awsSettings.images_bucket_name,
    },
  });

  const currentDateString = new Date().toISOString().replace(/\:|\./g, '-');
  const bodystream = new Buffer(parsedLink.imgUrl, 'binary');
  const imageUrlDomain = parseDomain(parsedLink.linkUrl).domain;

  const params = {
    Key: `${parsedLink.id}/${imageUrlDomain}_${currentDateString}${parsedLink.imgType}`,
    ContentType: parsedLink.imageMime,
    ContentEncoding: 'base64',
    Body: bodystream,
  };

  const resultPromise = await bucket.upload(params).promise();
  return resultPromise.Location;
};

If I want to use saveImage function, I get the error message.

module.exports.addTestObject = async (ctx) => {
  const testObj = ctx.request.body;
  try {
    switch (testObj.type) {
      case interestT.getType.link: {
        const knexTestObject = TestObject.knex();
        transaction(knexTestObject, trx =>
            TestObject.query(trx)
              .insert({
                interestDate: testObj.date,
              })
              .then(newInterest => {
                // save image
                if (parsedLink.saveImg) {
                  parsedLink.imgUrl = await saveImage(testObj);
                }

                newInterest.$relatedQuery('linkInterestsRel', trx).insert({
                  linkHeader: testObj.linkHeader,
                }),
              }
              ),
          )
          .then((linkInterest) => {
            console.log(linkInterest);
          })
          .catch((err) => {
            throw err;
          });
        break;
      }
      default:
        break;
    }
    ctx.response.body = interestObj;
  } catch (err) {
    const statusCode = err.status || 400;
    ctx.throw(statusCode, err.message);
  }
};
Bucentaur answered 9/1, 2018 at 16:32 Comment(4)
You can only use await in an async function, and your .then() callback is not async.Boyce
-> .then(async (newInterest) => {Lysippus
@JonasW. Thanks, can you write it as an answer? Then I can close this question.Bucentaur
Uh, don't use then callbacks within async functions.Sense
L
57

Regular functions run synchronously till they return. Therefore you cannot use await inside them as you cannot wait for an asynchronous event in a synchronous way.

JavaScript also has async functions, which look like regular functions, but are conceptually quite different: They run synchronously till they reach an await, then they stop and continue once the awaited Promise resolves. As such they cannot return their result synchronously, instead they return a Promise which then resolves when the function finished execution.

Therefore you need to convert your function into an async function:

 async function getUsername() { // <-- async keyword here
    return (await getUser()).name; // <-- await can be used inside
 }

Now this does also work inside a .then callback:

 getUser().then(async function(user) {
    const friends = await getFriends(user);
    // ...
 })

But this somewhat mixes the abstraction async functions with their underlying primitive Promise. If you would just await the Promise instead of adding a .then callback, the code gets way more readable:

 (async function() {
    const user    = await getUser();
    const friends = await getFriends(user);
 })();

The concrete question could be rewritten as:

 const linkInterest = await transaction(knexTestObject, async trx => {
     const newInterest = await TestObject.query(trx)
          .insert({  interestDate: testObj.date,   });

     if (parsedLink.saveImg) {
       parsedLink.imgUrl = await saveImage(testObj);
     }

    await newInterest.$relatedQuery('linkInterestsRel', trx)
       .insert({  linkHeader: testObj.linkHeader, }),
});
Lysippus answered 9/1, 2018 at 16:38 Comment(2)
The transaction callback still would need to be an async function if one wanted to use await for the query (as one indeed should).Sense
Clearest explanation I've seen of how to use await instead of .thenBun

© 2022 - 2024 — McMap. All rights reserved.