1. Introduction

This article requires some knowledge of promises and generators

  • Generators can be seen in my previous article on iterators and generators

2. Nature of async/await

Before, I only knew how to use async/await. I only knew that the code written after await is similar to that written in promise’s then, but I didn’t know what its internal nature is. Today finally understand the record

Async /await is essentially syntactic sugar for Generator and Promise

3. Use of async/await

function requestData(url) {
  return new Promise((resolve, reject) = > {
    setTimeout(() = > {
      resolve(url)
    }, 1000)})}async function foo() {
  const res1 = await requestData('aaa')
  const res2 = await requestData(res1 + 'bbb')
  const res3 = await requestData(res2 + 'ccc')
  console.log(res3)
}

foo()
Copy the code

Above we define a function foo that simulates asynchronous request data and call it with async await.

This code should print after 3 seconds

4. Use Generate function

If you think about the function foo above, Generate would look something like this

function* generatorFoo() {
	const res1 = yield requestData('aaa')
  const res2 = yield requestData(res1 + 'bbb')
  const res3 = yield requestData(res2 + 'ccc')
  console.log(res3)
}

generatorFoo()
Copy the code

But obviously the generator function above returns a generator, and it is impossible to execute the internal code without calling the next method, so how can we achieve the async/await result above?

So here it is

const generate = generatorFoo()
generate.next().value.then(res1= > {
  generate.next(res1).value.then(res2= > {
    generate.next(res2).value.then(res3= > {
      generate.next(res3)
    })
  })
})
Copy the code

Explain the above code

Line 1: Calling the generator function returns a generator

Line 2: Call the next method to perform the first yield of generatorFoo, return the promise to the generator (in the generator’s value property), and then call the Promise’s then method to get the data for the requestData(‘ AAA ‘) asynchronous request

Line 3: Generator generate calls the next method to perform a second yield, but this time passes the data from the first request as an argument. The second yield execution also returns a promise to the generator (in the generator’s value property) and then calls the Promise’s then method to retrieve the data for the requestData(RES1 + ‘BBB ‘) asynchronous request

Line 4: Same as line 3

Call the next method to pass back the asynchronous request’s RES to perform the final console.log(res3)

5. In the end

The above code requires us to manually call the next method several times, but we can do some automatic encapsulation

function execGenerator(generatorFn) {
  const generator = generatorFn()
  function exec(res) {
    const result =  generator.next(res)
    if(result.done) {
      return result.value
    }
    result.value.then(res= > {
      exec(res)
    })
  }
  exec()
}
execGenerator(foo)
Copy the code

The above encapsulates an execGenerator automation function that receives a generator function

The logic is a recursive logic. Exec encapsulates a function exec in which the generator’s next method is executed. If the generator returns a value with the done attribute false, the exec function is recursively called. If the generator returns a value with the done attribute false, the exec function is recursively called.