Callbacks, Promises and Async/Await

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

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

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

让咱们尝试按顺序打印字母A,B,C:dom

function printAll(){
  printString("A")
  printString("B")
  printString("C")
}
printAll()
复制代码

每次调用printAll时,您会注意到A,B和C以不一样的随机顺序打印!异步

这是由于这些函数是异步的。每一个函数按顺序执行,但每一个函数都独立于它本身的setTimeout。在开始以前,他们不会等待最后一个功能完成。async

这很是烦人,因此让咱们用回调修复它。函数

Callbacks

回调是传递给另外一个函数的函数。第一个函数完成后,它将运行第二个函数。ui

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

你能够看到,修改原始函数是很是容易的,可使用回调。spa

再次,让咱们尝试按顺序打印字母A,B,C:code

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~

相关文章
相关标签/搜索