目录
一、前言
先看一个例子:
const fs = require('fs')
//a.txt文件内容是aaa
fs.readFile('a.txt', 'utf8', function(err, data){
console.log(data);
})
console.log("123456");
这个例子的预期功能,就是读取并输出a.txt文件的内容"aaa",然后再输出“123456”,然而看输出却与预期不一样:
这就引出了异步和回调的概念。
二、异步与回调
nodejs是一个单线程函数,主线程在执行的时候,一旦发生了异步处理(文件读写、网络请求、定时任务、读取数据库等),一方面,js会让操作系统相关部件去处理这些请求,另一方面,它会继续执行后面的代码,这就是异步。
然后,当js让操作系统相关部件去处理这些请求,当这些请求有返回数据时(比如网络请求返回数据了),js就会调用相应的事件对象里的处理函数,这个处理函数,就是回调函数。
通俗的讲,就是js不管你有没处理完异步函数,就开始往下走了,除非异步函数处理的速度极快极快,才能出现“按代码顺序执行”的情况。
三、解决方案
①把需后面执行的程序,放到异步函数内,例如如下:
const fs = require('fs')
//a.txt文件内容是aaa
fs.readFile('a.txt', 'utf8', function(err, data){
console.log(data);
console.log("123456");
})
这样做可以解决问题,但是会引入一个问题,就是如果嵌套多了,代码会不美观,这种写法又称为“回调地狱”
②使用Promise
Promise是在ES6的标准中出现的,也就是nodejs v8.5.0以上版本,低于这个版本不能使用(版本查看命令:node -v)
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject,它们是两个函数,由js引擎内部提供,不用自己部署。
resolved函数,在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数,在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
const fs = require('fs')
const aPromise = new Promise((resolve, reject) => {
fs.readFile('a.txt', 'utf8', function(err, data){
if (err) return reject(err)
resolve(data)
})
})
const bPromise = new Promise((resolve, reject) => {
resolve("123456");
})
//then的作用执行Promise并返回结果
//这里可以理解为:aPromise.then(执行结果),return bPromise, bPromise.then(执行结果)
aPromise
.then(Content1 => {
console.log(Content1);
return bPromise
})
.then(Content2 => {
console.log(Content2);
})