Async
em Frente

Romário da Silva Lima

  • reles Front-end (6+ EXP)
  • Ex-Vizir, indo para Easynvest
  • Gosto de batata e gosto de estudar
Charlinho, o menino que so queria estudar

JS async-flow Evolution

Porrr quê?

Atender demandas

{facilitar a leitura do código}

Callbacks

A base

Anatomia


getSomething(somethingId, (err, data) => {
  if (err) {
    // :(
    return
  }
  // tudo certo :)
})
                  

getSomething(somethingId, success, failure)
                  

FAILSHOP

Callback Hell (Ryu)


getUserInfo(userId, (err, userInfo) => {
 if (err) {
   return
 }

 getFoo(userInfo.attributeId, (err, foo) => {
   // ...
   getBar(foo, (err, bar) => {
     // ...
     getAlfredinho(bar, (err, alfredinho) => {
       // ...
       giveMySoulBack(alfredinho, (err, soul) => {
        // ...
        pursuitFreedom(soul)
       })
     })
   })
 })
})
                      

Promises

Promise é igual a um...


function pegarPoteDeSorvete(pote) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (pote.conteudo instanceof Sorvete) {
        resolve(pote.conteudo)
        return
      }

      reject(pote.conteudo)
    }, 5000)
  })
}

pegarPoteDeSorvete(poteDaGeladeira)
.then(sorvete => console.log('Hoje Tem :)'))
.catch(feijao => console.log('Hoje Tem Janta :('))
      
.then
.catch

function getUserAddress(userId, cb) {
  getUserInfo(userId, (userInfoError, userInfo) => {
    if (userInfoError) {
      cb(userInfoError)
      return
    }

    cep(userInfo.cep, (cepError, address) => {
      if (cepError) {
        cb(cepError)
        return
      }

      cb(null, address)
    })
  })
}
                      

function getUserAddress(userId) {
  return getUserInfo(userId)
  .then(userInfo => cep(userInfo.cep))
  .catch(handleError)
}
      

Mããããs... eles querem mais

Querem escrever código async de uma maneira sync

O objetivo


function getUserAddress(userId) {
  const userInfo = getUserInfo(userId)
  const userAddress = cep(userInfo.cep)

  return userAddress
}
    

Generators

"Generator por Generator"

Pausável ;) Tenho múúúltiplos valores :* Retorno um Iterator

Anatomia


function *aleatorio() {
  yield 'Eu';
  yield 'gosto de';
  return 'batata.';
}

const iterator = aleatorio(); // {}
iterator.next() // { value: 'Eu', done: false }
iterator.next() // { value: 'gosto de', done: false }
iterator.next() // { value: 'batata.', done: true }
          

function *fib() {
  let current = 0
  let next = 1

  yield current

  while (true) {
    [current, next] = [next, current + next]
    yield current
  }
}
      

Generator tem dupla personalidade

Iterator

yield generator.next().value

throw try { generator.next() } catch(err) { ... }

done if (generator.next().done) { }

Observer

generator.next(10) data

generator.throw('não tem biscoito') error

generator.returns(10) return

Interação async com cara de sync


function *getUserAddress(userId) {
  const userInfo = yield getUserInfo(userId)
  const address = yield cep(userInfo.cep)

  return address
}

spawn(getUserAddress('zulu-zulu-1')).then().catch()
      

async iteration

Consumer


        
          const generator = getUserAddress('zulu-zulu-1')
        
        
          let result = generator.next()
        
        
          result.then(/* ... */)
        
        
          { cep: '05361-000' }
        
        
          result = generator.next({ cep: '05361-000' })
        
        
          result.then(/* ... */)
        
        
          { cep: '05361000', state: 'SP', /* ... */ }
        
        
          result = { cep: '05361000', state: 'SP', /* ... */ }
        
      

Producer


        
          const userInfo = yield getUserInfo('zulu-zulu-1')
        
        
          const userInfo = { cep: '05361-000' }
        
        
          const address = yield cep(userInfo.cep)
        
        
          const address = { cep: '05361000', state: 'SP', /* ... */ }
        
      

async iteration

Consumer


function spawn(generator) {
  return new Promise((resolve, reject) => {
    const onResult = lastPromiseResult => {
      const { value, done } = generator.next(lastPromiseResult)
      if (!done) {
        value.then(onResult, reject)
        return
      }
      resolve(value)
    }
    onResult()
  })
}
      

Producer


function *getUserAddress(userId) {
  const userInfo = yield getUserInfo(userId)
  const address = yield cep(userInfo.cep)

  return address
}

spawn(getUserAddress('zulu-zulu-1'))
      

Async / Await

No babel mais perto de você

TC39
Maturity Stages

Stage 0 Strawman

Stage 1 Proposal

Stage 2 Draft

Stage 3 Candidate

Anatomia


async function getUserAddress(userId) {
  const userInfo = await getUserInfo(userId)
  const address = await cep(userInfo.cep)

  return address
}
      

{Syntax Sugar}

Há muito mais por aí...

{ async function *() } { for await (const x of iterable) } { Observables (RxJS) }

Links

{Vídeo} Async Programming in ES7 | JSConf US 2015
(apenas assista)

{Livro} You Don't Know JS: Async & Performance
(fundamental para entender o {async-flow})

{Artigo} ES6 Generators [PT-BR]
(excelente escrito pelo Vizir João (gato) Kiyoshi)

{Artigo} Tasks, microtasks, queues and schedules
(para entender como o event loop funciona de uma perspectiva async)