node
同步、异步API的概念:
同步API:从上往下执行,当前代码执行完后,才会继续往下执行,范例:
console.log(1)
console.log(2)
// 1
// 2
异步API:当前代码的执行不会阻塞后续代码的执行,范例:
console.log(1)
setTimeout(() => {
console.log(2)
}, 1000)
console.log(3)
// 1
// 3
// 等待1秒后
// 2
同步API我们是可以直接用返回值获取结果的,但是异步API是不行的,异步API需要用回调函数的形式,用回调函数的形参接收返回结果
console.log(1)
// 同步代码在执行时,这个setTimout也会执行,只不过回调函数当前不会调用,会先推入到异步回调队列中,等达到执行条件了,就会调用
setTimout(() => {
console.log(2)
}, 1000)
console.log(3)
回调地狱:指的是多个依次的异步操作,说白了就是回调函数嵌套,当嵌套层次过多,不利于阅读和维护
Promise基本使用:
const fs = require('fs')
// 这个resolve和reject是我们自己定义名字,你可以改成其他,但是不推荐,业内约定俗成就叫这个
const p = new Promise((resolve, reject) => {
fs.readFile('./hehe.txt', 'utf8', (err, data) => {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})
p.then((data) => {
// 异步API执行正确,拿到正确的数据
// your code . do something...
}).catch((err) => {
// 异步API执行异常,拿到错误的数据
// your code... do something...
})
- Promise就是用来解决回调地狱的,,它不是一个新的技术,只是一种手段,是异步编程的中间产物
- 原理:把一个异步API封装起来,将异步API的结果以回调函数的形式传递出去
- 可以通过new Promise( ( resolve, reject ) => { … }) 创建Promise实例
- 注意:创建实例时,并不会执行
( resolve, reject ) => { ... }
回调函数,也就意味着内部的代码都不会执行,只有在调用then或catch方法的时候才会去调用
- 注意:创建实例时,并不会执行
- 可以通过resolve( result )方法传递正确的结果
- 可以通过reject( err )方法传递错误的结果
- 通过调用Promise实例的then(( result ) => { … })方法接收正确的结果
- 通过调用Promise实例的catch(( err ) => { … })方法接收错误的结果
解决回调地狱:
const fs = require('fs')
// 想要依次读取1.txt,2.txt,3.txt的文件内容
// fs.readFile('./1.txt', 'utf8', (err, data) => {
// console.log(data)
// fs.readFile('./2.txt', 'utf8', (err, data) => {
// console.log(data)
// fs.readFile('./3.txt', 'utf8', (err, data) => {
// console.log(data)
// })
// })
// })
// new Promise(cb) 实例时,并不会调用这个 cb 函数
// 只有在调用了Promise实例的then方法或catch方法,才会调用cb函数
const p1 = new Promise((yes, no) => {
fs.readFile('./1.txt', 'utf8', (err, data) => {
yes(data)
})
})
const p2 = new Promise((yes, no) => {
fs.readFile('./2.txt', 'utf8', (err, data) => {
yes(data)
})
})
const p3 = new Promise((yes, no) => {
fs.readFile('./3.txt', 'utf8', (err, data) => {
yes(data)
})
})
// then函数的返回值 就是 其参数(回调函数)的返回值
p1.then(data => {
console.log(data)
return p2
}).then(data => {
console.log(data)
return p3
}).then(data => {
console.log(data)
})
异步函数(ES7添加的):
- async关键字:
- 在普通函数前面加上
async
关键字,该普通函数就变成了异步函数 - 异步函数的返回值会被包装成一个
Promise
实例- 用
return
传递正确的结果,相当于Promise里面的resolve函数 - 用
throw
传递错误的结果,相当于Promise里面的reject函数,一旦抛出错误,后面的代码就不会执行了
- 用
- 在普通函数前面加上
- await关键字:
- await后面一般跟Promise实例(其实也可以跟其他的数据,如果是其他的数据,则直接返回),await可以阻塞后续的代码,等待Promise实例返回结果后,再继续向下执行
- await可以直接拿到Promise实例的正确结果,错误结果需要用
try ... catch
或catch(err => err)
(推荐用这个)来获取 - await只能出现在异步函数(亲爸爸)中
范例:用async、await关键字改造依次读取1.txt、2.txt、3.txt文件的代码:
const fs = require('fs')
// promiseify可以将node中现有的基于回调函数形式的异步API,改造成返回Promise实例的函数
const { promiseify } = require('util')
// fs.readFile('./1.txt', 'utf8', (err, data) => { ... })
const readFileOfPromise = promiseify(fs.readFile)
(async () => {
const data1 = await readFileOfPromise('./1.txt', 'utf8')
console.log(data1)
const data2 = await readFileOfPromise('./2.txt', 'utf8')
console.log(data2)
const data3 = await readFileOfPromise('./3.txt', 'utf8')
console.log(data3)
})()