Callbacks, Promises and Async/Await

本文转自作者Sandeep Dinesh的文章:Callbacks, Promises and Async/Await

假定你有一个函数能够在一段随机的时候后打印一个字符串:

function printString(string){
  setTimeout(
    () => {
      console.log(string)
    }, 
    Math.floor(Math.random() * 100) + 1
  )
}

让我们尝试按递次打印字母A,B,C:

function printAll(){
  printString("A")
  printString("B")
  printString("C")
}
printAll()

每次挪用printAll时,您会注意到A,B和C以差别的随机递次打印!

这是由于这些函数是异步的。每一个函数按递次实行,但每一个函数都自力于它自己的setTimeout。在最先之前,他们不会守候末了一个功用完成。

这异常烦人,所以让我们用回调修复它。

Callbacks

回调是通报给另一个函数的函数。第一个函数完成后,它将运转第二个函数。

function printString(string, callback){
  setTimeout(
    () => {
      console.log(string)
      callback()
    }, 
    Math.floor(Math.random() * 100) + 1
  )
}

你能够看到,修正原始函数是异常轻易的,能够运用回调。

再次,让我们尝试按递次打印字母A,B,C:

function printAll(){
  printString("A", () => {
    printString("B", () => {
      printString("C", () => {})
    })
  })
}
printAll()

嗯,代码如今很貌寝,但至少它有用!每次挪用printAll时,都邑获得雷同的效果。

回调的题目是它建立了一个名为“Callback Hell”的东西。基本上,你最先在函数内的函数内嵌套函数,而且最先变得异常难以浏览代码。

Promise

Promise尝试修复这个嵌套题目。让我们转变我们的功用来运用Promises

function printString(string){
  return new Promise((resolve, reject) => {
    setTimeout(
      () => {
       console.log(string)
       resolve()
      }, 
     Math.floor(Math.random() * 100) + 1
    )
  })
}

你能够看到它看起来依然异常类似。您将全部函数包装在Promise中,而不是挪用回调,而是挪用resolve(假如涌现毛病则谢绝)。该函数返回此Promise对象。

再次,让我们尝试按递次打印字母A,B,C:

function printAll(){
  printString("A")
  .then(() => {
    return printString("B")
  })
  .then(() => {
    return printString("C")
  })
}
printAll()

这被称为许诺链。您能够看到代码返回函数的效果(将是Promise),并将其发送到链中的下一个函数。

代码不再嵌套,但看起来依然很杂沓!

经由历程运用箭头函数的功用,我们能够删除“包装器”功用。代码变得更清楚,但依然有许多不必要的括号:

function printAll(){
  printString("A")
  .then(() => printString("B"))
  .then(() => printString("C"))
}
printAll()

Await

Await基本上是Promises的语法糖。它使您的异步代码看起来更像是同步/历程代码,人类更轻易明白。

该PRINTSTRING功用不自许的版本在一切转变。

再次,让我们尝试按递次打印字母A,B,C:

async function printAll(){
  await printString("A")
  await printString("B")
  await printString("C")
}
printAll()

是啊…。好多了!

您可能会注意到我们对包装函数printAll运用“async”关键字。这让我们的JavaScript晓得我们正在运用async / await语法,假如你想运用Await,这是必要的。这意味着你不能在环球范围内运用Await; 它老是须要一个包装函数。大多数JavaScript代码都在函数内部运转,因而这不是什么大题目。

等等,这里另有更多哦

该PRINTSTRING函数不返回任何东西,是自力的,一切我们体贴的是递次。然则,假如您想猎取第一个函数的输出,在第二个函数中实行某些操纵,然后将其通报给第三个函数,该怎么办?

我们不是每次都打印字符串,而是建立一个衔接字符串并通报它的函数。

Callbacks

这里是回调款式:

function addString(previous, current, callback){
  setTimeout(
    () => {
      callback((previous + ' ' + current))
    }, 
    Math.floor(Math.random() * 100) + 1
  )
}

为了运用它:

function addAll(){
  addString('', 'A', result => {
    addString(result, 'B', result => {
      addString(result, 'C', result => {
       console.log(result) // Prints out " A B C"
      })
    })
  })
}
addAll()

不太好。

Promises

这是Promise作风:

function addString(previous, current){
  return new Promise((resolve, reject) => {
    setTimeout(
      () => {
        resolve(previous + ' ' + current)
      }, 
      Math.floor(Math.random() * 100) + 1
    )
  })
}

为了运用它:

function addAll(){  
  addString('', 'A')
  .then(result => {
    return addString(result, 'B')
  })
  .then(result => {
    return addString(result, 'C')
  })
  .then(result => {
    console.log(result) // Prints out " A B C"
  })
}
addAll()

运用箭头函数意味着我们能够使代码更好一些:

function addAll(){  
  addString('', 'A')
  .then(result => addString(result, 'B'))
  .then(result => addString(result, 'C'))
  .then(result => {
    console.log(result) // Prints out " A B C"
  })
}
addAll()

这一定更具可读性,特别是假如你向链增加更多,但依然是一堆括号。

Await

该功用与Promise版本保持一致。

而且为了运用它:

async function addAll(){
  let toPrint = ''
  toPrint = await addString(toPrint, 'A')
  toPrint = await addString(toPrint, 'B')
  toPrint = await addString(toPrint, 'C')
  console.log(toPrint) // Prints out " A B C"
}
addAll()

Yeah. SO MUCH BETTER~

    原文作者:Becky
    原文地址: https://segmentfault.com/a/1190000018140170
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞