node.js异步编程初探2
问题:如果异步API后面的代码执行,依赖当前异步API的执行结果,但实际上后续代码在执行的时候异步API还没有返回结果,这个问题怎么解决?
例如:
如果需要一次读取多个文件。
解决方案一:
const fs = require('fs');
fs.readFile('./1.txt', 'utf8', (err, result1) => {
console.log(reult1);
fs.readFile('./2.txt', 'utf8', (err, result2) => {
console.log(reult2);
fs.readFile('./3.txt', 'utf8', (err, result3) => {
console.log(reult3);
})
})
})
//输出结果
1
2
3
缺点
回调的多层嵌套,虽然能过解决需求,但会形成回调地狱的现象,不利于后期的维护。
解决方案二:
这是一种异步编程语法上的改进,可以将异步API的执行和结果的处理进行分离。
promise是构造函数。
基础代码形式:
将异步API的执行和结果的处理进行分离。
const fs = require('fs');
let promise = new Promise((resolve, reject) => {
fs.readFile('./1.txt', 'utf8', (err, result) => {
if (err != null) {
reject(err);
} else {
resolve(result);
}
})
});
promise.then((result) => {
console.log(result);
})
.catch((err) => {
console.log(err);
})
Promise解决回调地狱的问题
//此代码有点问题,promises解决回调地狱的形式就是这样的
function p1() {
return new Promise((resolve, reject) => {
fs.readFile('./1.txt', 'utf8', (err, result) => {
console.log(result);
})
});
}
function p2() {
return new Promise((resolve, reject) => {
fs.readFile('./2.txt', 'utf8', (err, result) => {
console.log(result);
})
});
}
function p3() {
return new Promise((resolve, reject) => {
fs.readFile('./3.txt', 'utf8', (err, result) => {
console.log(result);
})
});
}
p1().then((r1) => {
console.log(r1);
return p2();
}).then((r2) => {
console.log(r2);
return p3();
}).then((r3) => {
console.log(r3);
})
解决方案三(最优):
使用async关键字:
1.在普通函数前面加上async关键字,普通函数就变成了异步函数。
2.异步函数默认的返回值是promise对象,省去了需要new promise的步骤
3.在异步函数的内部使用return关键字进行结果返回,结果会被包裹在promise对象中,return关键字替代了resolve方法。
4.在异步函数的内部使用throw关键字对错误进行抛出。
5.调用异步函数再链式调用then方法获取异步函数执行结果。
6.调用异步函数再链式调用catch方法获取异步函数执行的错误信息。
例如:
async function fn() {
throw 'err'
return 123;
}
fn().then((data) => {
console.log(data);
}).catch((err) => {
console.log(err);
})
await关键字:
1.await只能出现在异步函数中
2.awiat后面只能跟promise对象,写其他类型的API是不可以的
3.await可以暂停异步函数向下执行 等待promise对象返回结果后再向下执行
由此:
异步代码------------->同步代码
const fs = require('fs');
const promisify = require('util').promisify; //promisify可对现有的异步API进行包装,让其返回promise对象
const readFile = promisify(fs.readFile); //readFile就是一个新的可以返回promise对象的方法
async function run() {
let r1 = await readFile('./1.txt', 'utf8');
let r2 = await readFile('./2.txt', 'utf8');
let r3 = await readFile('./3.txt', 'utf8');
console.log(r1);
console.log(r2);
console.log(r3);
}
run();