1.
什么是回调函数
回调函数是指通过函数参数的方式将一个函数传递到另一个函数中,参数函数就是回调函数。
function
A
() {
console
.
log
(
"A is running"
)
}
function
B
(
callback
) {
console
.
log
(
"B Start"
)
callback
()
// A is running
console
.
log
(
"B End"
)
}
B
(
A
)
我们经常将回调函数写成
callback
,实际上它是
call then back
的简写,含义是调用后返回,就是
在主函数中调用参数函数,参数函数调用完成后返回主函数继续执行主函数中的代码。
为什么在
B
函数中不直接调用
A
函数而要通过参数的方式传递进去
?
通常在编写应用程序时,
B
函数都是语言内部或者其他开发者定义好的,我们看不到内部代码或者
说不能直接在他内部代码中插入我们的代码,而我们又想介入程序的执行,此时就可以通过回调函
数的方式将我们的逻辑传递给
B
函数,
B
函数在内部再来调用这个回调函数。
2.
回调函数传递参数
在主函数中调用回调函数时,可以为回调函数传递参数。
function
A
(
arg
) {
console
.
log
(
"A is running"
)
console
.
log
(
arg
)
}
function
B
(
callback
) {
console
.
log
(
"B Start"
)
callback
(
"
我是
B
函数传递给
A
函数的参数
"
)
// A is running
console
.
log
(
"B End"
)
}
B
(
A
)
3.
回调函数在异步编程中的应用
在异步编程中,异步
API
执行的结果就是通过回调函数传递参数的方式传递到上层代码中的。
const
fs
=
require
(
"fs"
)
fs
.
readFile
(
"./index.html"
,
"utf-8"
,
function
(
error
,
data
) {
if
(
error
)
console
.
log
(
"
发生了错误
"
)
console
.
log
(
data
)
})
4.
回调地狱
回调地狱是回调函数多层嵌套导致代码难以维护的问题。
基于回调函数的异步编程一不小心就会产生回调地狱的问题。
const
fs
=
require
(
"fs"
)
fs
.
readFile
(
"./x.txt"
,
"utf-8"
,
function
(
error
,
x
) {
fs
.
readFile
(
"./y.txt"
,
"utf-8"
,
function
(
error
,
y
) {
fs
.
readFile
(
"./z.txt"
,
"utf-8"
,
function
(
error
,
z
) {
console
.
log
(
x
)
console
.
log
(
y
)
console
.
log
(
z
)
})
})
})
const
x
=
fs
.
readFile
(
'./x.txt'
,
'utf-8'
)
const
y
=
fs
.
readFile
(
'./y.txt'
,
'utf-8'
)
const
z
=
fs
.
readFile
(
'./z.txt'
,
'utf-8'
)
console
.
log
(
x
)
console
.
log
(
y
)
console
.
log
(
z
)
4.7
基于
Promise
的异步编程
1. Promise
概述
Promise
是
JavaScript
中异步编程解决方案,可以解决回调函数方案中的回调地狱问题。
可以将
Promise
理解为容器,用于包裹异步
API
的容器,当容器中的异步
API
执行完成后,
Promise
允许我们在容器的外面获取异步
API
的执行结果,从而避免回调函数嵌套。
function
A
(
arg
) {
console
.
log
(
"A is running"
)
console
.
log
(
arg
)
}
function
B
(
callback
) {
console
.
log
(
"B Start"
)
callback
(
"
我是
B
函数传递给
A
函数的参数
"
)
// A is running
console
.
log
(
"B End"
)
}
B
(
A
)
const
fs
=
require
(
"fs"
)
fs
.
readFile
(
"./index.html"
,
"utf-8"
,
function
(
error
,
data
) {
if
(
error
)
console
.
log
(
"
发生了错误
"
)
console
.
log
(
data
)
})
const
fs
=
require
(
"fs"
)
fs
.
readFile
(
"./x.txt"
,
"utf-8"
,
function
(
error
,
x
) {
fs
.
readFile
(
"./y.txt"
,
"utf-8"
,
function
(
error
,
y
) {
fs
.
readFile
(
"./z.txt"
,
"utf-8"
,
function
(
error
,
z
) {
console
.
log
(
x
)
console
.
log
(
y
)
console
.
log
(
z
)
})
})
})
const
x
=
fs
.
readFile
(
'./x.txt'
,
'utf-8'
)
const
y
=
fs
.
readFile
(
'./y.txt'
,
'utf-8'
)
const
z
=
fs
.
readFile
(
'./z.txt'
,
'utf-8'
)
console
.
log
(
x
)
console
.
log
(
y
)
console
.
log
(
z
)
Promise
翻译为承若,表示它承若帮我们做一些事情,既然它承若了它就要去做,做就会有一个过
程,就会有一个结果,结果要么是成功要么是失败。
所以在
Promise
中有三种状态
,
分别为等待
(pending)
,成功
(fulfilled)
,失败
(rejected)
。
默认状态为等待,等待可以变为成功,等待可以变为失败。
状态一旦更改不可改变,成功不能变回等待,失败不能变回等待,成功不能变成失败,失败不能变
成成功。
2. Promise
基础语法
const
fs
=
require
(
"fs"
)
const
promise
=
new
Promise
(
function
(
resolve
,
reject
) {
fs
.
readFile
(
"./x.txt"
,
"utf-8"
,
function
(
error
,
data
) {
if
(
error
) {
//
将状态从等待变为失败
reject
(
error
)
}
else
{
//
将状态从等待变为成功
resolve
(
data
)
}
})
})
promise
.
then
(
function
(
data
) {
console
.
log
(
data
)
})
.
catch
(
function
(
error
) {
console
.
log
(
error
)
})
3. Promise
链式调用
const
fs
=
require
(
"fs"
)
function
readFile
(
path
) {
return new
Promise
(
function
(
resolve
,
reject
) {
fs
.
readFile
(
path
,
"utf-8"
,
function
(
error
,
data
) {
if
(
error
)
return
reject
(
error
)
resolve
(
data
)
})
})
}
readFile
(
"./x.txt"
)
.
then
(
function
(
x
) {
console
.
log
(
x
)
return
readFile
(
"./y.txt"
)
})
.
then
(
function
(
y
) {
console
.
log
(
y
)
return
readFile
(
"./z.txt"
)
})
.
then
(
function
(
z
) {
console
.
log
(
z
)
})
.
catch
(
function
(
error
) {
console
.
log
(
error
)
})
.
finally
(
function
() {
console
.
log
(
"finally"
)
})
4. Promise.all
并发异步操作
const
fs
=
require
(
"fs"
)
Promise
.
all
([
readFile
(
"./x.txt"
),
readFile
(
"./y.txt"
),
readFile
(
"./z.txt"
)
]).
then
(
function
(
data
) {
console
.
log
(
data
)
})
4.8
基于异步函数的异步编程
Promise
虽然解决了回调地狱的问题,但是代码看起来仍然不简洁。
使用异步函数简化代码提高异步编程体验。
1.
异步函数概述
const
fs
=
require
(
"fs"
)
function
readFile
(
path
) {
return new
Promise
(
function
(
resolve
,
reject
) {
fs
.
readFile
(
path
,
"utf-8"
,
function
(
error
,
data
) {
if
(
error
)
return
reject
(
error
)
resolve
(
data
)
})
})
}
async function
getFileContent
() {
let
x
=
await
readFile
(
"./x.txt"
)
let
y
=
await
readFile
(
"./y.txt"
)
let
z
=
await
readFile
(
"./z.txt"
)
return
[
x
,
y
,
z
]
}
getFileContent
().
then
(
console
.
log
)
async
声明异步函数的关键字,异步函数的返回值会被自动填充到
Promise
对象中。
await
关键字后面只能放置返回
Promise
对象的
API
。
await
关键字可以暂停函数执行,等待
Promise
执行完后返回执行结果。
await
关键字只能出现在异步函数中。
2. util.promisify
在
Node.js
平台下,所有异步方法使用的都是基于回调函数的异步编程。为了使用异步函数提高异
步编程体验,可以使用
util
模块下面的
promisify
方法将基于回调函数的异步
API
转换成返回
Promise
的
API
。
const
fs
=
require
(
"fs"
)
const
util
=
require
(
"util"
)
const
readFile
=
util
.
promisify
(
fs
.
readFile
)
async function
getFileContent
() {
let
x
=
await
readFile
(
"./x.txt"
,
"utf-8"
)
let
y
=
await
readFile
(
"./y.txt"
,
"utf-8"
)
let
z
=
await
readFile
(
"./z.txt"
,
"utf-8"
)
return
[
x
,
y
,
z
]
}
getFileContent
().
then
(
console
.
log
)