下面是对Node.js异步编程的整理,希望可以帮助到有需要的小伙伴~
同步API:只有当API执行完成后,才能继续执行下一个API
异步API:当前API的执行不会阻塞后续代码的执行
// 同步编程
/*
console.log("before");
console.log("after");
// before
// after
*/
// 异步编程
console.log('before');
setTimeout(
() => {
console.log('last')
},2000);
console.log('after');
/*
before
after
last
// before执行后,2秒钟后再执行last,在这2秒钟的时间里after执行了
*/
同步API可以从返回值中拿到API执行的结果
异步API必须通过回调函数拿到异步操作的执行结果
通过回调函数获取异步函数的返回值
回调函数:
别人调用自己定义的函数
// 回调函数的定义
function getData (callback) {
}
// 回调函数的调用
getData ( ()=>{
} );// getData()里面的实参()=>{} 对应的是 callback形参;即在getData()函数内部调用了()=>{}函数
通过回调函数获取异步函数的返回值示例:
/* function getMsg () {
setTimeout(function () {
return {
msg:'hello node.js'
}
},2000)
}
const msg = getMsg();
console.log(msg); // undefined
// 2秒后才可以执行定时器里面的内容
// 所以返回值是函数的默认返回值undefined */
// 可以通过回调函数获取到异步操作的执行结果
function getMsg (callback) {
setTimeout(function () {
callback({
msg:'hello node.js'
})
},2000)
}
getMsg(function (data){
console.log(data); // { msg: 'hello node.js' }
})
Node.js从上而下依次执行代码
遇到同步API就拿到同步代码执行区去执行
遇到异步API就拿到异步代码执行区,但是不会执行异步代码,
当所有的同步代码执行完毕后,再到异步代码执行区依次执行代码
当异步代码执行完毕后,系统会去回调函数队列中找异步API对应的回调函数,把回调函数放到同步代码执行去区执行
同步API从上到下依次执行,前面代码会阻塞后面代码的执行
for (var i=0;i<10;i++) {
console.log(i)
}
console.log("循环外")
// 0 1 2 3 4 5 6 7 8 9 循环外
异步API不会等待API执行完成后再向下执行代码
console.log('代码开始执行')
setTimeout(function(){
console.log('2s后执行')
},2000)
setTimeout(function(){
console.log('0s后执行')
})
console.log('代码结束执行')
/* 代码开始执行
代码结束执行
0s后执行
2s后执行 */
异步编程的返回结果是通过回调函数获取的
在异步编程中,前面代码的执行不会阻碍后面代码的执行,但是有时候后面代码的执行会依赖前面代码的执行结果,这时可以通过多个回调函数来完成。
读取文件就是通过回调函数返回结果的,如果依次读取多个文件,就需要多次调用回调函数
示例如下:
// 依次读取1.txt、 2.txt 、 3.txt文件
// 导入文件模块
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)
})
})
})
/*
// 结果:
1
2
3
*/
如果需要写很多个回调函数的话,就会造成回调地狱,promise可以解决回调地狱问题。
Promise出现的目的是解决Node.js异步编程中回调地狱的问题。
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)); // 失败了
通过Promise对象的then方法获取到异步的执行结果。
// 依次读取1.txt、 2.txt 、 3.txt文件
// 导入文件模块
const fs = require('fs');
const {
resolve } = require('path');
// 读取文件
/* 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)
})
})
}) */
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);
})
})
}
p1().then((r1) => {
console.log(r1);
return p2();
})
.then((r2) => {
console.log(r2);
return p3();
})
.then((r3) => {
console.log(r3);
})
// 相当于
/* p1().then((r1) => {
console.log(r1);
});
p2().then((r2) => {
console.log(r2);
});
p3().then((r3) => {
console.log(r3);
}); */
/*
// 结果:
1
2
3
*/
使用Promise可以解决回调地狱的问题,但是会产生代码冗余,可以使用ES 7提供的回调函数解决回调地狱的问题并且代码更加简单明了。
异步函数是异步编程语法的终极解决方案,它可以让我们将异步代码写成同步的形式,让代码不再有回调函数嵌套,使代码变得清晰明了。
const fn = async () => {
};
async关键字:
await关键字:
示例:
const fs = require('fs');
// fs中readFile()方法的返回结果不是Promise类型的,不能使用异步函数中的await关键字
// uitl模块的promisify()方法可以将返回的结果改为Primise类型
// 没有调用promisify方法,没有写promisify()
// 改在现有异步函数的API,让其返回promise对象,从而支持异步函数语法
const promisify = require('util').promisify;
// 调用了promisify()方法,但没有调用readFile()方法
// 调用promisify方法改造现有异步API,让其返回promise对象
const readFile = promisify(fs.readFile);
async function run() {
// 调用readFile()方法,该方法的返回结果回改成promise类型
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();
// 返回结果:
// 1
// 2
// 3
end~
对Node.js异步编程的介绍到这里就结束啦~
希望可以对你有所帮助~
如果有错误,请大佬指正,万分感谢!