SoFunction
Updated on 2025-03-10

Understand the usage of async&await in Koa2

Koa is a very famous Node server-side framework, with versions and versions. The former uses generator for asynchronous operations, while the latter uses the latest async/await solution

When I first used this writing method, I encountered a problem, the code is as follows:

const Koa = require('koa');
const app = new Koa();

const doSomething = time => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('task done!')
    }, time)
  })
}

// Used to print request information((ctx, next) => {
  (`${}:::${}`)
  next()
})

(async ctx => {
  const result = await doSomething(3000)
  (result);
   = result
})

(3000);

Let's test it: curl http://localhost:3000

Expected results:

(3 seconds later...) task done!

However, the reality is:

(immediately)
Not Found

What the hell? Why didn't it be performed as expected? This requires us to understand how middleware in Koa is connected in series. Flip through the source code and connect middlewares into the code as follows:

function compose (middleware) {
 return function (context, next) {
  // This index is used to count to prevent next from being called multiple times  let index = -1
  // Execution portal  return dispatch(0)
  
  function dispatch (i) {
   // If next is called multiple times, an exception will be reported   if (i <= index) return (new Error('next() called multiple times'))
   index = i
   // Take out the first middleware   let fn = middleware[i]
   // Execute the first next as the last function   if (i === ) fn = next
   if (!fn) return ()
   try {
    /**
     This is the key, what does it mean?
      There are three forms of the method:
     
      (value);
      (promise);
      (theanable);
     
     All three forms will produce a new promise.  in:

     The first form provides the ability to customize the value of a Promise, which corresponds to a reason.  The difference between the two lies in the different states of the obtained Promise.

     The second form provides the ability to create a copy of a Promise.

     The third form is to convert a Promise-like object into a real Promise object.  One of its important functions is to encapsulate a Promise object from other implementations into a Promise object currently implemented.  For example, you are using bluebird, but now there is a Q Promise, then you can turn Q Promise into a bluebird Promise through this method.  The second form can be classified into the third
    
     **/
    return (fn(context, function next () {
     // Execute the next middleware, and the return result is also a promise     return dispatch(i + 1)
    }))
   } catch (err) {
    return (err)
   }
  }
 }
}

With the above foundation, let's take a look at the previous question again. Why did the response return immediately without waiting for the second middleware execution to be completed?

Because the first middleware is not an asynchronous function.

Since each next method is executed, a Promise object is actually returned. So if we perform an asynchronous operation in a middleware and want to wait for it to complete, we must add await before executing this middleware

Let's rewrite the previous code

(async (ctx, next) => {
  (`${}:::${}`)
  await next()
})

(async ctx => {
  const result = await doSomething(3000)
  (result);
   = result
})

OK, no problem, everything is executed as expected: clap:

Error handling

With the help of Promise's powerful skills and async/await syntax, we only need to write the try/catch operation in the outermost middleware to catch all the subsequent middleware exceptions!

(async (ctx, next) => {
  try{
    await next()
  }catch(err){
    (err)
  }
})

(async (ctx)=>{
  throw new Error('something wrong!')
   = 'Hello'
})

Full control based on middleware chains and the fact that Promise is based on makes everything easy to operate. No longer everywhere if (err) return next(err) but only promise

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.