node 异步编程
2020年7月20日同步API,异步API
- 同步API只有当前API执行完成后,才能继续执行下一个API
- 当前API的执行不会阻塞后续代码的执行
- 同步API可以从返回值中拿到API执行结果但是异步API是不可以的
- 基本上有回调方法的是异步,没有回调方法的是同步(个人总结仅供参考)
- 同步API从上到下依次执行,前面的代码会阻塞后面的代码
- 异步API不会等待API执行完成后,再去执行下面代码
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 |
/** * 一个普通回调函数 * @param callback */ function getAge(callback) { callback('18') //执行 } /** * 一个定时回调(异步) * @param callback */ function getData(callback) { setTimeout(() => { callback('异步方法中的值') //执行 }, 2000) } /** * 调用 getAge 方法匿名函数里的形参接收数据 */ getAge((age) => { console.log(age) }) /** * 调用 getData 方法匿名函数里的形参接收数据 */ getData((data) => { console.log(data) }) |
promise避免地狱回调
什么是地狱回调直接上代码,这就地狱回调,我要依次读取1~6.txt文件,只有上一个成功才能读取下一个,文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
const fs = require('fs'); fs.readFile('./1.txt', 'utf8', (err, result1) => { console.log(result1) fs.readFile('./2.txt', 'utf8', (err, result2) => { console.log(result2) fs.readFile('./3.txt', 'utf8', (err, result3) => { console.log(result3) fs.readFile('./4.txt', 'utf8', (err, result4) => { console.log(result4) fs.readFile('./5.txt', 'utf8', (err, result5) => { console.log(result5) fs.readFile('./6.txt', 'utf8', (err, result6) => { console.log(result6) }) }) }) }) }) }); |
promise出现的目的是解决Node.js异步编程中,回调地狱的问题,基本使用
1 2 3 4 5 6 7 8 9 10 11 12 13 |
let promise = new Promise((resolve, reject) => { setTimeout(() => { if (true) { resolve('执行方法成功了') //通过形参中的方法返回成功结果 } else { reject('执行方法失败了') //通过形参中的方法返回错误结果 } }, 2000) }) promise.then(success => console.log(success)) .catch(error => console.log(error)) |
promise的链式操作避免地狱回调(重点)
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 |
const fs = require('fs') function p1() { return new Promise((resolve, reject) => { fs.readFile('./1.txt', 'utf8', (err, result) => { resolve(result) }) }); } function p2() { return new Promise((resolve, reject) => { fs.readFile('./2.txt', 'utf8', (err, result) => { resolve(result) }) }); } function p3() { return new Promise((resolve, reject) => { fs.readFile('./3.txt', 'utf8', (err, result) => { resolve(result) }) }); } /** * 我要获取 1.txt文件后, 再获取2.txt文件后, 再获取3.txt * 这样就可以避免地狱回调的问题 */ p1().then((r1) => { console.log(r1); return p2(); //直接return 下一 then 调用的方法,连接上 }) .then((r2) => { console.log(r2); return p3(); //直接return 下一 then 调用的方法,连接上 }) .then((r3) => { console.log(r3) }) |
使用async 和 await解决地狱回调比使用promise简单
异步函数是异步编程语法的终极解决方案,他可以让我们异步代码写成同步代码的形式,让代码不再有回调函数嵌套,使代码变的清晰明了
async关键字
- 普通函数定义前加async关键字,普通函数变成异步函数
- 异步函数默认返回promise对象
- 在异步函数内使用return关键字进行结果返回 结果会被包裹在promise对象中 return 关键字代替了resolve方法
- 在异步函数内使用throw关键字抛出程序异常
- 调用异步函数在链式调用then方法获取异步函数执行结果
- 调用异步函数在链式调用catch方法获取异步函数执行的错误信息
await关键字
- await关键只能出现在异步函数中
- await promise ; await只写promise对象其他对象是不可以的
- await 关键字可是暂停异步函数向下执行 知道 promise返回结果
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 46 47 48 49 50 51 52 53 54 55 56 57 58 |
const fs = require('fs') /** * 使用async 关键字将普通方法改为异步方法 * 异步函数默认返回值是promise对象 * @returns {Promise<number>} */ async function p1() { return 1 throw '返回错误信息'; //错误信息后后面的代码就不执行了 和return 用同样的功能 } async function p2() { return 2 throw '返回错误信息'; } async function p3() { return 3 throw '返回错误信息'; } /** * 使用链式调用 */ p1().then((r1) => { console.log(r1); return p2(); //直接return 下一 then 调用的方法,连接上 }) .then((r2) => { console.log(r2); return p3(); //直接return 下一 then 调用的方法,连接上 }) .then((r3) => { console.log(r3) }) /** * 使用await 关键字调用 * @returns {Promise<void>} */ async function run(){ /** * await 具有将异步方法变为同步方法的功能, * 但是所加的方法前面必须返回promise对象, * 而且await 必须加载 async 函数里 */ let r1 = await p1() let r2 = await p2() let r3 = await p3() console.log(r1) console.log(r2) console.log(r3) } run() |
使用util promisify 改造现有异步api,让其返回promise对象
使用这种方式是不是比地狱回调好多了^_^
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
const fs = require('fs') //应用文件读取模块 const promisify = require('util').promisify //调用util对象的promise方法 const readFile = promisify(fs.readFile) //改造方法让其放回promise对象 async function run() { let r1 = await readFile('./1.html', 'utf8') let r2 = await readFile('./2.html', 'utf8') let r3 = await readFile('./3.html', 'utf8') console.log(r1) console.log(r2) console.log(r3) } run() |