
深入理解 promise、generator+co、async/await 用法
回调函数因为涉及的内容多而杂,并且在项目中也不怎么使用,所以在这里就先不说了,
本章重点讲解一下 Promise
、generator + co
、async/await
因为里面内容会有点多,并且还有好多代码示例。所以需要静下心慢慢看,相信看完之后,你肯定会对这三种方法涉及的异步问题的理解更上一层楼
如果想要大致了解一下的话,可以看看我的这篇文章《JS中异步处理方案》
咱们先说 Promise
,然后慢慢涉及到其他,循序渐进(其实这是JS处理异步的一个发展流程)
开始吧!!!
Promise
Promise 简单的说就是一个容器,里面保存着某个未来才会结束的时间(通常是一个异步操作)的结果。从语法上说,Promise 就是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法处理。
如何理解:
- 没有异步就不需要 promise
- promise 本身不是异步,只是我们去编写异步代码的一种方式
promise 有所谓的 4 3 2 1
4 大术语
一定要结合异步操作来理解
既然是异步,这个操作需要有个等待的过程,从操作开始,到获取结果,有一个过程的
- 解决(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
它是 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
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
返回结果后,在继续执行
这三种方法都是用来解决异步的,很很很重要
通常到公司面试的时候,面试官都会问到:
- 说一下异步的发展流程
- 说一下异步的解决方案
那么看完本章内容就派上大用场了哦!