同步 API :只有当前 API 执行完成后,才能继续执行下一个 API
console.log('before');
console.log('after');
异步 API :当前 API 的执行不会阻塞后续代码的执行
console.log('before');
setTimeout(
() => { console.log('last');
}, 2000);
console.log('after');
异步 API 执行结果需要用回调函数获取
function getMsg (callback) {
setTimeout(function () {
callback ({ msg: 'Hello Node.js' })
}, 2000);
}
getMsg (function (msg) {
console.log(msg);
});
同步API、异步API执行顺序
同步 API 会阻塞后面代码的执行,需要从上往下依次执行,异步 API 不会阻塞后面代码的执行
代码运行时,同步代码会放在同步代码执行区,异步代码会放在异步代码执行区和回调函数队列,等待所有同步代码完成后,再回调异步代码执行。
但如果需要依次按顺序执行三个异步 API 最简单的方法是不断的异步 API,但那将会造成异步编程的回调地狱问题
例如:需求依次读取 A 文件、B 文件、C 文件
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)
})
})
});
这样的代码将会非常难维护
所以nodejs添加了一个 Promise 对象,目的是解决Node.js异步编程中回调地狱的问题。
Promise 对象
Promise 对象用于表示一个异步操作的最终完成 (或失败),及其结果值。
下面是 promise 对象的一个最基本结构
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
if (true) {
resolve({name: '张三'})
}else {
reject('失败了')
}
}, 2000);
});
promise.then(result => console.log(result); // {name: '张三'})
.catch(error => console.log(error); // 失败了)
其中,resolve 和 reject 是函数带的两个参数,在执行成功时,会在 promise.then 函数里接收 resolve 的返回值作为参数,失败则在 .catch 函数里接收 reject 的返回值作为参数。
程序可以写为如下
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)
})
});
}
//把创建的 promise 对象作为函数返回值
p1().then((r1)=> {
console.log(r1);
return p2();
})
.then((r2)=> {
console.log(r2);
return p3();
})
.then((r3) => {
console.log(r3)
})
异步函数
异步函数是异步编程语法的终极解决方案,它可以让我们将异步代码写成同步的形式,让代码不再有回调函数嵌套,使代码变得清晰明了
const fn = async () => {};
async function fn () {}
- 普通函数定义前加 async 关键字 普通函数变成异步函数
- 异步函数默认返回 promise 对象
- 在异步函数内部使用 return 关键字进行结果返回 结果会被包裹的 promise 对象中 return 关键字代替了 resolve 方法
- 在异步函数内部使用 throw 关键字抛出程序异常
- 调用异步函数再链式调用 then 方法获取异步函数执行结果
- 调用异步函数再链式调用 catch 方法获取异步函数执行的错误信息
await关键字
- await 关键字只能出现在异步函数中
- await promise, await 后面只能写 promise 对象 写其他类型的API是不不可以的
- await 关键字可是暂停异步函数向下执行 直到 promise 返回结果
async function p1 () {
return 'p1';
}
async function p2 () {
return 'p2';
}
async function p3 () {
return 'p3';
}
async function run () {
let r1 = await p1()
let r2 = await p2()
let r3 = await p3()
console.log(r1)
console.log(r2)
console.log(r3)
}
run();