同步(sync)API和异步(async)API
-
同步API:顺序执行,上一个API执行完再执行下一个API
-
异步API:当前API执行不会阻塞后续代码执行
同步和异步API获取结果的方式
- 同步API可以直接通过返回值(return)获取代码执行结果
- 异步API无法通过返回值获取结果,可以通过回调函数的参数获取API执行结果
回调地狱
当前异步API后面的代码需要用到当前API的返回结果,比如要依次读取a.txt,b.txt,c.txt三个文件的内容
由于readFile是异步API,要想顺序获取abc三个文件的内容,就要层层嵌套,这样的代码是不能维护的,称为回调地狱
const fs = require('fs');
fs.readFile('./a.txt', 'utf8', (err, result1) => {
console.log(result1)
fs.readFile('./b.txt', 'utf8', (err, result2) => {
console.log(result2)
fs.readFile('./c.txt', 'utf8', (err, result3) => {
console.log(result3)
})
})
});
node.js 异步编程
1. Promise
Promise是一个构造函数,出现的目的是为了解决回调地狱的问题
用法如下:将异步API包裹在promise里面,实现了在异步API外面得到API执行的结果
let promise = new Promise((resolve, reject) => { // 实例化Promise ,返回promise对象
// resolve reject 是函数 resolve用于返回API结果,reject用于返回错误信息
setTimeout(() => {
if (true) {
resolve('2s 后定时器成功执行');
} else {
reject('出错了');
}
}, 2000);
});
// 调用promise对象的then方法 获取异步API的执行结果,也就是resolve返回的内容
promise.then(result => {
console.log(result);
})
.catch(err => { // 调用catch方法 获取错误信息,也就是reject返回的内容
console.log(err);
});
promise解决回调地狱问题:
const fs = require('fs');
let f1 = () => {
return new Promise((resolve, reject) => {
fs.readFile('./a.txt', 'utf8', (err, doc) => {
resolve(doc);
})
})
}
let f2 = () => {
return new Promise((resolve, reject) => {
fs.readFile('./b.txt', 'utf8', (err, doc) => {
resolve(doc);
})
})
}
let f3 = () => {
return new Promise((resolve, reject) => {
fs.readFile('./c.txt', 'utf8', (err, doc) => {
resolve(doc);
})
})
}
f1().then(result => {
console.log(result);
return f2();
}).then(result => {
console.log(result);
return f3();
}).then(result => {
console.log(result);
})
2. 异步函数 ES7新增
声明一个异步函数只需要在函数前面加上async关键字即可,异步函数默认返回的是一个promise对象
let fn = async() => { // 返回一个promise对象
//throw ('出错了'); // 代替reject方法
return ('123'); // 代替resolve方法
}
fn().then(result => {
console.log(result);
})
.catch(result => {
console.log(result);
});
let fn = async() => { // 返回一个promise对象
// throw ('出错了'); // 代替reject方法
return ('123'); // 代替resolve方法
}
async function run() {
// await关键字必须在异步函数里,可以直接得到结果
// await关键字 后面必须跟promise对象
console.log(await fn()); // 123
}
run();
利用异步函数解决回调地狱问题:
const fs = require('fs');
// promisify方法能够将现有的异步API改造成异步函数
const promisify = require('util').promisify;
// 将fs中的readFile方法改造成异步函数 返回异步函数
const readFile = promisify(fs.readFile);
// readFile就是一个异步函数,他的返回值是promise对象
async function run() {
let r1 = await readFile('./a.txt', 'utf8');
let r2 = await readFile('./b.txt', 'utf8');
let r3 = await readFile('./c.txt', 'utf8');
console.log(r1);
console.log(r2);
console.log(r3);
}
run();