异步编程

2021-7-20 Node.js

回调函数callback,Promise

# 回调函数callback

函数也是一种数据类型,既可以当做参数进行传递,也可以当作方法的返回值。

回调函数并不是函数自调用,而是将函数作为参数。一般情况下,把函数作为参数的目的就是为了获取函数内部的异步操作结果。异步是因为js是单线程的,对一些耗时的异步操作放在后面执行可提高性能。

异步操作:

  • setTimeout
  • readFile
  • writeFile
  • readdir
  • ajax

往往异步API都伴随一个回调函数。

function add(x, y, callback) {
  setTimeout(function () {
    var ret = x + y
    callback(ret)
  })
}
add(10, 20, function (ret) {
  console.log(ret)//使用回调函数是为了方便拿到异步操作结果,并做一些其他操作
})
1
2
3
4
5
6
7
8
9

# Promise

callback hell:回调地狱,保证了异步操作的执行顺序,但嵌套太深,难以维护。

Promise使用场景:同一个地方需要请求多个接口的数据,此时请求操作都要同步,方便拿到所有数据进行处理。

foo

为了解决回调地狱嵌套问题,所以在ES6中新增了一个API:Promise

  • Promise是一个构造函数,它本身不是异步,但内部往往都是封装一个异步任务
  • Promise容器一旦创建,就开始执行里面的代码
console.log(1)

//创建Promise容器,容器里面放的是异步任务
var p1 = new Promise(function (resolve, reject) {//参数1:解决,参数2:失败
  console.log(2)
  fs.readFile('./a.txt', 'utf8', function (err, data) {//异步任务
    if (err) {
      //操作失败了
      reject(err)//调用了then方法的第二个参数函数
    } else {
      //操作成功了
      console.log(3)
      resolve(data)//调用了then方法的第一个参数函数
    }
  })
})
console.log(4)//执行顺序是1 2 4 3,虽然Promise会立即执行,但当发现里面是异步操作,又往下先执行了

//当p1成功了,就执行then中指定的操作
p1.then(function (data) {//这里的function就是resolve
  console.log(data)
}, function (err) {//这里的function指的是reject
  console.log('读取文件失败了', err)
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# Promise嵌套调用

var p1 = new Promise(function (resolve, reject) {
  fs.readFile('./a.txt', 'utf8', function (err, data) {//异步任务
    if (err) {
      reject(err)
    } else {
      resolve(data)
    }
  })
})

var p2 = new Promise(function (resolve, reject) {
  fs.readFile('./b.txt', 'utf8', function (err, data) {//异步任务
    if (err) {
      reject(err)
    } else {
      resolve(data)
    }
  })
})

var p3 = new Promise(function (resolve, reject) {
  fs.readFile('./c.txt', 'utf8', function (err, data) {//异步任务
    if (err) {
      reject(err)
    } else {
      resolve(data)
    }
  })
})

//then的链式调用
p1.then(function (data) {//这里的function就是resolve
  console.log(data)
  //当p1读取成功时
  return p2 //return了一个Promise对象,接着后面就是p2.then()
}, function (err) {//这里的function指的是reject
  console.log('读取文件失败了', err)
})
.then(function (data) {//这里指的是p2的resolve
  console.log(data)
  return p3
})
.then(function (data) {
  console.log(data)
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# 封装Promise版本的readFile

function pReadFile(filePath) {
  return new Promise(function (resolve, reject) {
    fs.readFile(filePath, 'utf8', function (err, data) {//异步任务
      if (err) {
        reject(err)
      } else {
        resolve(data)
      }
    })
  })
}

pReadFile('./a.txt')
  .then(function (data) {
    console.log(data)
    return pReadFile('./b.txt')
  })
  .then(function (data) {
    console.log(data)
    return pReadFile('./c.txt')
  })
  .then(function (data) {
    console.log(data)
  })
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24