回调函数由于涉及的内容多而杂,而且在项目中也不怎么使用,因此在这里就先不说了,node
本章重点讲解一下 Promise
、generator + co
、async/await
git
由于里面内容会有点多,而且还有好多代码示例。因此须要静下心慢慢看,相信看完以后,你确定会对这三种方法涉及的异步问题的理解更上一层楼面试
若是想要大体了解一下的话,能够看看个人这篇文章《JS中的异步解决方案》npm
我们先说Promise
,而后慢慢涉及到其余,按部就班(其实这是JS处理异步的一个发展流程)数组
开始吧!!!promise
Promise
Promise简单的说就是一个容器,里面保存着某个将来才会结束的时间(一般是一个异步操做)的结果。从语法上说,Promise就是一个对象,从它能够获取异步操做的消息。Promise提供统一的API,各类异步操做均可以用一样的方法处理。bash
如何理解:异步
4大术语
必定要结合异步操做来理解
既然是异步,这个操做须要有个等待的过程,从操做开始,到获取结果,有一个过程的async
- 解决(fulfill)指一个 promise 成功时进行的一系列操做,如状态的改变、回调的执行。虽然规范中用 fulfill 来表示解决,但在后世的 promise 实现多以 resolve 来指代之
- 拒绝(reject)指一个 promise 失败时进行的一系列操做
- 终值(eventual value)所谓终值,指的是 promise 被解决时传递给解决回调的值,因为 promise 有一次性的特征,所以当这个值被传递时,标志着 promise 等待态的结束,故称之终值,有时也直接简称为值(value)
- 据因(reason)也就是拒绝缘由,指在 promise 被拒绝时传递给拒绝回调的值
3种状态
在异步操做中,当操做发出时,须要处于等待状态
当操做完成时,就有相应的结果,结果有两种:编辑器
- 成功了
- 失败了
一共是3种状态,以下:
- 等待态(Pending (也叫进行态)
- 执行态(Fulfilled)(也叫成功态)
- 拒绝态(Rejected) (也叫失败态)
![]()
针对每一种状态,有一些规范:
等待态(Pending)
处于等待态时,promise 需知足如下条件:
- 能够迁移至执行态或拒绝态
执行态(Fulfilled)
处于执行态时,promise 需知足如下条件:
- 不能迁移至其余任何状态
- 必须拥有一个不可变的终值
拒绝态(Rejected)
处于拒绝态时,promise 需知足如下条件:
- 不能迁移至其余任何状态
- 必须拥有一个不可变的据因
2种事件
针对3种状态,只有以下两种转换方向:
- pending –> fulfilled
- pendeing –> rejected
在状态转换的时候,就会触发事件:
- 若是是pending –> fulfiied,就会触发onFulFilled事件
- 若是是pendeing –> rejected,就会触发onRejected事件
在调用resolve方法或者reject方法的时候,就必定会触发事件
须要注册onFulFilled事件 和 onRejected事件
针对事件的注册,Promise对象提供了then方法,以下:
promise.then(onFulFilled,onRejected)
针对 onFulFilled,会自动提供一个参数,做为终值(value)
针对 onRejected,会自动提供一个参数,做为据因(reason)
1个对象
promise
注:只有异步操做的结果,能够决定当前是哪种状态,任何其余的操做都没法改变这个状态
当咱们建立 promise
时,会默认的处于 Pending
状态,而且在建立的时候,promise
中必定要有一个执行器,而且这个执行器会当即执行
// ()=>{} 叫执行器,会当即执行
let p = new Promise(()=>{ })
// 刚建立的Promise默认处理Pending状态
console.log(p) // Promise { <pending> }
复制代码
在 promise
的执行器中须要传入两个参数,分别是 resolve
和 reject
,在内部调用时,就分别表明状态由 pending=>fulfilled(成功) pending=>rejected(失败)
而且一旦 promise
状态发生变化以后,以后状态就不会再变了。好比:调用 resolve
以后,状态就变为 fulfilled
,以后再调用 reject
,状态也不会变化
let p = new Promise((resolve,reject)=>{
resolve("有钱了....") // 如今promise就处理成功态
})
console.log(p) // Promise { '有钱了....' }
//失败态就不演示了
复制代码
切记状态发生变化以后,以后状态就不会再变了
// 一个promise的状态只能从等待到成功,或从等待到失败
let p = new Promise((resolve,reject)=>{
resolve("有钱了...") // 成功了....
reject("没钱了...") // 失败了....
})
p.then(()=>{
console.log("成功了....")
},()=>{
console.log("失败了...")
})
//只能输出 成功了...
复制代码
then
方法上面代码已经看到了,在使用时能够经过promise
对象的内置方法then
进行调用,then
有两个函数参数,分别表示promise
对象中调用resolve
和reject
时执行的函数
let p = new Promise((resolve,reject)=>{
// resolve("有钱了...") // 成功了....
reject("没钱了...") //失败了....
})
// 在then方法中,有两个参数
// 第一个参数表示从等待状到成功态,会调用第1个参数
// 第二个参数表示从等待状到失败态,会调用第2个参数
p.then(()=>{
console.log("有钱了....")
},()=>{
console.log("没钱了...")
})
//输出结果 没钱了...
复制代码
在执行完后,成功确定有一个成功的结果 失败确定有一个失败的缘由,那么如何获得成功的结果 ? 如何获得失败缘由呢?
let p = new Promise((resolve,reject)=>{
// 调用reolve时,能够把成功的结果传递下去
// resolve("有钱了...") // 成功了...
// 调用reject时,能够把失败的缘由传递下去
reject("没钱了...") // 失败了....
})
p.then((suc)=>{
console.log(suc)
},(err)=>{
console.log(err)
})
//输出结果 没钱了...
复制代码
当咱们在执行失败处理时,也能够用 throw
,就是抛出一个错误对象,也是失败的
以下:
let p = new Promise((resolve,reject)=>{
// throw 一个错误对象 也是失败的
throw new Error("没钱了...")
})
p.then((suc)=>{
console.log(suc)
},(err)=>{
console.log(err)
})
复制代码
throw
的定义:throw
语句用来抛出一个用户自定义的异常。当前函数的执行将被中止(throw
以后的语句将不会执行),而且控制将被传递到调用堆栈中的第一个catch
块。若是调用者函数中没有catch
块,程序将会终止。
//尝试一下
function getRectArea(width, height) {
if (isNaN(width) || isNaN(height)) {
throw "Parameter is not a number!";
}
}
try {
getRectArea(3, 'A');
}
catch(e) {
console.log(e);
// expected output: "Parameter is not a number!"
}
复制代码
promise自己是同步的
// promise自己是同步的
console.log("start")
let p = new Promise(()=>{
console.log("哈哈") // 哈哈
})
console.log("end")
//输出顺序 start 哈哈 end
复制代码
而且在执行器的内部也是能够写异步代码的
那么then
中的方法何时调用呢?
只有当调用resolve
,reject
时才会去执行then
中的方法**
let p = new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log("setTimeout")
// resolve("有钱了...")
reject("没钱了...")
},1000)
})
p.then((suc)=>{
console.log(suc) // 有钱了...
},(err)=>{
console.log(err) // 没钱了...
})
复制代码
首先咱们在目录下面建两个文件,分别是:name.txt
和 age.txt
name.txt
文件里写了一个 age.txt
age.txt
文件里写了一个 666
下面就以读取文件为例,来演示链式调用(须要了解一点node基础)
当你读取文件的时候,若是你用的是 vscode 编辑器,里面会有一个小bug,用相对路径可能会出错,因此最好使用绝对路径
读取文件:
let fs = require("fs")
let path = require("path")
let filename = path.join(__dirname,"name.txt")
fs.readFile(filename,"utf8",(err,data)=>{
if(err){
console.log(err)
}
fs.readFile(path.join(__dirname,data),"utf8",(err,data)=>{
if(err){
console.log(err)
}
console.log(data)
})
})
//输出结果 666
复制代码
若是用这种方法,就会出现 回调地狱 ,很难受,因此通常不用
在读取文件时,咱们能够专门 封装一个函数 ,功能就是读取一个文件的内容
let fs = require("fs")
// 封装一个函数,函数的功能是读取一个文件的内容
// rest参数(下去本身了解一下,就是能够获取到传过来的全部内容)
function readFile(...args){
return new Promise((resolve,reject)=>{
fs.readFile(...args,function(err,data){
if(err) reject(err)
resolve(data)
})
});
}
//读文件
readFile("./name.txt","utf8").then(data=>{
console.log(data)
},err=>{
console.log(err)
})
//输出结果 age.txt
复制代码
若是文件不存在,会走第二个函数
let fs = require("fs")
function readFile(...args){
return new Promise((resolve,reject)=>{
fs.readFile(...args,function(err,data){
if(err) reject(err)
resolve(data)
})
});
}
// 若是name1不存在,走then的第2个函数
readFile("./name1.txt","utf8").then(data=>{
console.log(data)
},err=>{
console.log(err)
})
//报错 no such file or directory
复制代码
那么若是咱们想要读取age.txt
里面的内容呢?
咱们能够这么写:
let fs = require("fs")
function readFile(...args){
return new Promise((resolve,reject)=>{
fs.readFile(...args,function(err,data){
if(err) reject(err)
resolve(data)
})
});
}
readFile("./name.txt","utf8").then(data=>{
// console.log(data) // age.txt
readFile(data,"utf8").then(data=>{
console.log(data) // 666
},err=>{
console.log(err)
})
},err=>{
console.log(err)
})
//输出结果 666
复制代码
这样写就能够获取到age.txt
文件里面的内容,可是呢,这样写又回到了 回调地狱 ,不是说这种方法不行,而是不够优雅
使用 链式调用
在promise
中能够链式调用 就是 .then
以后,还能够 .then
,你能够无数次的 .then
.then
以后又返回了一个新的 promise
,就是.then
的函数参数中会默认返回promise
对象,因此当你碰到.then
连续调用的时候,你就能够把前面的全部代码当成一个promise
let fs = require("fs")
function readFile(...args){
return new Promise((resolve,reject)=>{
fs.readFile(...args,function(err,data){
if(err) reject(err)
resolve(data)
})
});
}
readFile("./name.txt","utf8").then(data=>{
// console.log(data) // age.txt
return false;
},err=>{
console.log(err)
}).then(data=>{ // 这里面的data是上一个then中的第一个函数的返回值,这个.then前面的一坨代码就能够当成一个promise
console.log(data) // false
},err=>{
})
复制代码
若是没有这个文件,则返回错误信息
let fs = require("fs")
function readFile(...args){
return new Promise((resolve,reject)=>{
fs.readFile(...args,function(err,data){
if(err) reject(err)
resolve(data)
})
});
}
readFile("./name1.txt","utf8").then(data=>{
return data;
},err=>{
return err;
// console.log(err)
}).then(data=>{
console.log(data)
},err=>{
console.log(err)
})
//输出结果 no such file or directory
复制代码
可是若是咱们返回一个promise
呢?
那么这个promise
会执行,而且会采用他的状态
let fs = require("fs")
function readFile(...args){
return new Promise((resolve,reject)=>{
fs.readFile(...args,function(err,data){
if(err) reject(err)
resolve(data)
})
});
}
readFile("./name.txt","utf8").then(data=>{
return data;
},err=>{
return err;
// console.log(err)
}).then(data=>{
// console.log(data)
return new Promise((resolve,reject)=>{ //返回一个promise
reject("不OK") //下面的.then采用这个状态(失败态)
})
},err=>{}).then(data=>{
console.log(data)
},err=>{
console.log(err) // 不OK
})
//输出结果 不OK
复制代码
因此若是返回的是一个promise
,那么这个promise
会执行,而且会采用它的状态
小总结:
若是在上一个then
的第一个函数中,返回一个普通值,那么不管你是在第1个函数中返回,仍是在第2个函数中返回,都会做为下一个then的成功的结果,若是不返回,undefined
就做为下一个then的成功的结果
若是返回的是一个promise
,会做为下一个then
的promise
对象,data err去promise
对象中去取,也就是说,前一个then
的返回值,会做为后一个then
的参数
再给两个小例子,本身看一下:
let p = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("hello")
},1000)
})
p.then(data=>{
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("world")
},1000)
})
}).then(data=>{
console.log(data)
},err=>{
})
//输出结果 world
复制代码
let p = new Promise((resolve,reject)=>{
resolve("hello")
})
let p1 = p.then(data=>{
return new Promise((resolve,reject)=>{
setTimeout(()=>{
reject("不OK")
},1000)
})
})
p1.then(data=>{
console.log(data)
},err=>{
console.log(err)
})
//输出结果 不OK
复制代码
接下来讲一个小问题,链式调用中的 循环引用
有的人不喜欢把前面的一大堆代码后面加.then
,因此就用了下面的一种写法(有可能会出现 循环引用):
let p = new Promise((resolve,reject)=>{
resolve("hello")
})
let p1 = p.then(data=>{
return p1 //循环引用 报错 p1在等p1的状态改变,也就是我在等我吃饭,显然是不行的
})
p1.then(data=>{
console.log(data)
},err=>{
console.log("-----",err) //可执行,而后报错
})
复制代码
若是咱们把状态肯定住,那就能够了
let p = new Promise((resolve,reject)=>{
resolve("hello")
})
let p1 = p.then(data=>{
// return 123 至关于把等待态改变成成功态
return 123
})
p1.then(data=>{
console.log(data) // 123
},err=>{
console.log("-----",err)
})
//输出 123
复制代码
固然改变成失败态也能够
let p = new Promise((resolve,reject)=>{
resolve("hello")
})
let p1 = p.then(data=>{
// return new Error("不OK") 把等待态变成失败态
return new Error("不OK")
})
p1.then(data=>{
console.log(data)
},err=>{
console.log(err) // Error: 不OK
})
复制代码
看一个问题
let p = new Promise((resolve,reject)=>{
resolve("hello")
})
let p1 = p.then(data=>{
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("666")
},1000)
}))
},1000)
})
})
// data是promise 仍是666
p1.then(data=>{
console.log(data)
},err=>{
console.log(err)
})
复制代码
按理说,data打印出来的是一个promise
,就是上面resolve
里面的一堆代码
然而并非,promise
会 进行递归解析.到最后上面代码会打印出来 666
若是在resolve
或reject
中又是一个promise
,那么就会递归解析(不管有多少个promise
)
let p = new Promise((resolve, reject) => {
resolve("hello")
})
let p1 = p.then(data => {
return new Promise((resolve, reject) => {
resolve(new Promise((resolve, reject) => {
resolve(new Promise((resolve, reject) => {
resolve(new Promise((resolve, reject) => {
resolve(new Promise((resolve, reject) => {
resolve(new Promise((resolve, reject) => {
resolve("666")
}))
}))
}))
}))
}))
})
})
p1.then(data => {
console.log(data)
}, err => {
console.log(err)
})
//打印结果 666
复制代码
catch
方法catch
方法,用于注册 onRejected
回调catch
实际上是then
的简写,then(null,callback)
catch
就是.then
的语法糖
若是.then
中有第2个函数,在这个.then
后面又有catch
,若是到失败态,那么会走.then
的第2个函数
let p = new Promise((resolve,reject)=>{
reject("不OK")
})
p.then(data=>{
},err=>{
console.log("1",err)
}).catch(err=>{
console.log("2",err)
})
//输出结果 1 不OK
复制代码
若是.then
中没有第2个函数,在这个.then
后面又有catch
,若是到失败态,那么会走catch
let p = new Promise((resolve,reject)=>{
reject("不OK")
})
p.then(data=>{
}).catch(err=>{
console.log("2",err)
})
//输出结果 2 不OK
复制代码
在.then
第二个函数中,return err
这个 err 它是 return 到了下一个.then
的第一个函数中
let p = new Promise((resolve,reject)=>{
reject("不OK")
})
p.then(data=>{
},err=>{
// 在这里它并无reutrn到err中,它reutrn到第一个参数中
return err
}).then(data=>{
console.log("data----",data)
},err=>{
console.log("err----",err)
})
//输出结果 data---- 不OK
复制代码
因此最终:
一个promise
中,通常在then
中只有一个函数,在then
后面有一个catch
,通常使用then
来获取data
,在catch
中获取err
let p = new Promise((resolve,reject)=>{
resolve("OK")
})
p.then(data=>{
console.log(data)
}).catch(err=>{
console.log(err)
})
复制代码
在Pomise
类上面,提供了几个静态方法:
resolve
reject
finally
all
race
resolve
Promise.resolve("有钱了...").then(data=>{
console.log(data) // 有钱了...
})
复制代码
等价于下面这种写法:
let p = new Promise((resolve,reject)=>{
resolve("有钱了...")
})
p.then(data=>{
console.log(data)
})
复制代码
reject
Promise.reject("没钱了...").catch(data=>{
console.log(data) // 没钱了...
})
复制代码
finally
无论转成成功态仍是失败态,都会调用finally
这个方法
Promise.resolve("有钱").then(data=>{
console.log(data)
}).finally(()=>{
console.log("开心...")
})
//打印结果 有钱 开心...
复制代码
Promise.reject("没钱").catch(data=>{
console.log(data)
}).finally(()=>{
console.log("不开心...")
})
//打印结果 没钱 不开心...
复制代码
all
all
表示[ ]中的promise
都成功了,才能获得最终的值
注意里面是一个数组 读取name.txt
和age.txt
中的内容
let fs = require("fs").promises;
// all表示[]中的promise都成功了,才能获得最终的值
Promise.all([fs.readFile("./name.txt","utf-8"),fs.readFile("./age.txt","utf-8")]).then(data=>{
console.log(data) // [ 'age.txt', '666' ]
})
//打印结果 [ 'age.txt', '666' ]
复制代码
若是有一个不成功,那么就不行
let fs = require("fs").promises;
Promise.all([fs.readFile("./name1.txt","utf-8"),fs.readFile("./age.txt","utf-8")]).then(data=>{
console.log(data)
})
//这个是不行的
复制代码
race
顾名思义,race
就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪一个结果得到的快,就返回那个结果,无论结果自己是成功状态仍是失败状态。
let fs = require("fs").promises;
Promise.race([fs.readFile("./name.txt","utf-8"),fs.readFile("./age.txt","utf-8")]).then(data=>{
console.log(data) // age.txt
})
复制代码
改变文件里面的内容,多尝试几回
generator + co
我很佩服你能看到这里,厉害
先说 生成器 和 迭代器
生成器能够生成迭代器,可让程序中断,不会把 { } 中的代码所有执行
用法:在function
和本身声名的名称之间加一个 * 号,里面用yield
产出数据,而后调用生成器生成迭代器
function * read(){
yield 1; // 只有产出,并不执行
}
//调用生成器 生成 迭代器 it就是迭代器
let it = read()
复制代码
生成器能够产出不少值,迭代器只能next一下,拿一个值,next一下,拿一个值
function * read(){
yield 1;
}
let it = read()
console.log(it.next()) // { value: 1, done: false }
console.log(it.next()) // { value: undefined, done: true }
复制代码
function * read(){
yield 1;
yield 2;
yield 3;
}
// 调用read() 返回值是迭代器
let it = read()
console.log(it.next()) // { value: 1, done: false }
console.log(it.next()) // { value: 2, done: false }
console.log(it.next()) // { value: 3, done: false }
console.log(it.next()) // { value: undefined, done: true }
复制代码
若是 next 中有参数的话,那么他会把这个参数传给上一个生成器声明的变量里
因此第一个 next 中的参数没有任何意义,咱们通常不写
function * read(){
let a = yield 1;
console.log(a) // 9
let b = yield 2;
console.log(b) // 10
let c = yield 3;
console.log(c) // 11
}
let it = read()
console.log(it.next()) // { value: 1, done: false }
console.log(it.next(9)) // { value: 2, done: false }
console.log(it.next(10)) // { value: 3, done: false }
console.log(it.next(11)) // { value: undefined, done: true }
复制代码
接下来用这个实现咱们的读文件操做,哈哈,是否是很恶心
读取name.txt
文件
const fs = require("fs").promises;
// 生成器
function * read(){
yield fs.readFile("./name.txt","utf-8")
}
// 迭代器
let it = read()
// console.log(it.next()) // { value: Promise { <pending> }, done: false }
it.next().value.then(data=>{ //由于是一个对象,因此直接.value
console.log(data)
})
//输出结果 age.txt
复制代码
而后读取age.txt
文件
const fs = require("fs").promises;
function * read(){
let concent = yield fs.readFile("./name.txt","utf-8")
yield fs.readFile(concent,"utf-8")
}
let it = read()
it.next().value.then(data=>{
// console.log(data)
// console.log(it.next(data)) // { value: Promise { <pending> }, done: false }
it.next(data).value.then(data=>{
console.log(data)
})
})
//输出结果 666
复制代码
也能够这样
const fs = require("fs").promises;
function * read(){
let concent = yield fs.readFile("./name.txt","utf-8")
let age = yield fs.readFile(concent,"utf-8")
return age
}
let it = read()
it.next().value.then(data=>{
it.next(data).value.then(data=>{
let r = it.next(data)
console.log(r) // { value: '666', done: true }
})
})
复制代码
是否是感受又陷入了 回调地狱
那么就用 co 吧
安装co npm i co
用上来:
const fs = require("fs").promises;
function * read(){
let concent = yield fs.readFile("./name.txt","utf-8")
let age = yield fs.readFile(concent,"utf-8")
return age
}
let co = require("co")
co(read()).then(data=>{
console.log(data) //
})
//输出结果 666
复制代码
是否是简单多了,爽不爽
co
库能够实现自动迭代
既然是自动执行,那么promise
的executor
中先执行一次it.next()
方法,返回value
和done
;value
是一个pending
的Promise
;若是done=false
,说明尚未走完,继续在value.then
的成功回调中执行下一次next
,即调用read
方法;直到done
为true
,走完全部代码,调用resolve
;中间有任何一次next
异常,直接调用reject
,中止迭代
总结:
function
关键字与函数名之间有一个星号yield
语句,定义不一样的内部状态yield
会将函数分割成好多个部分,每产出一次,就暂停一次Genenrator
是一个生成器,调用Genenrator
函数,不会当即执行函数体,只是建立了一个迭代器对象,如上例中的it
就是调用read
这个Generator
函数获得的一个迭代器next
方法,调用一次就会继续向下执行,直到遇到下一个yield
或return
next()
方法能够带一个参数,该参数会被当作上一条yield
语句的返回值,并赋值给yield
前面等号前的变量yield
,就会返回一个{value:xxx,done:bool}
的对象,而后暂停,返回的value
就是跟在yield
后面的返回值,done
表示这个generator
是否已经执行结束了return
时,return
后的值就是value
值,done
此时就是true
return
,就是隐含的return undefined
co
库,能够自动的将generator
迭代co
执行会返回一个promise
,用then
注册成功/失败回调co
将迭代器it
做为参数,这里每调用一次read
,就执行一次next
async/await
被称为 异步解决 的终极方案
async、await是什么?
async
顾名思义是“异步”的意思,async
用于声明一个函数是异步的。
而await
从字面意思上是“等待”的意思,就是用于等待异步完成。通俗来讲,就是await
在这里等待promise
返回结果了,再继续执行。而且await
只能在async
函数中使用
一般async
、await
都是跟随Promise
一块儿使用的。
为何这么说呢?由于 async
返回的都是一个Promise
对象,同时async
适用于任何类型的函数上。这样await
获得的就是一个Promise
对象(若是不是Promise
对象的话那async
返回的是什么 就是什么);
注: await
不只仅用于等 Promise
对象,它能够等任意表达式的结果,因此,await
后面实际是能够接普通函数调用或者直接量的(不演示了)
紧跟着上面的代码,再写一段
const fs = require("fs").promises;
async function read(){
let concent = await fs.readFile("./name.txt","utf-8")
let age = await fs.readFile(concent,"utf-8")
return age
}
read().then(data=>{
console.log(data) // 666
})
复制代码
是否是比上面的写法还爽呢?
await
命令后面的 Promise
对象,运行结果多是 rejected
,因此最好把 await
命令放在 try...catch
代码块中
以下:
async function myFunction() {
try {
await somethingThatReturnsAPromise();
} catch (err) {
console.log(err);
}
}
// 另外一种写法
async function myFunction() {
await somethingThatReturnsAPromise().catch(function (err){
console.log(err);
});
}
复制代码
总结:
async:
async
函数会返回一个Promise
对象async
函数中是return
一个值,这个值就是Promise
对象中resolve
的值async
函数中是throw
一个值,这个值就是Promise
对象中reject
的值await:
await
只能在async
函数中使用await
后面要跟一个promise
对象await
等promise
返回结果后,在继续执行这三种方法都是用来解决异步的,很很很重要
一般到公司面试的时候,面试官都会问到:
那么看完本章内容就派上大用场了哦!
好了本章就先到此结束了,咱们下期再见