本文转自作者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~