“约见”⾯试官系列之常见⾯试题第三⼗⼆篇之async和
await(建议收藏)
⼀、async和await
1. async和await的概念
1)async 函数是 Generator 函数的语法糖,使⽤ 关键字 async 来表⽰,在函数内部使⽤ await 来表⽰异步
2)ES7 提出的async 函数,终于让 JavaScript 对于异步操作有了终极解决⽅案
3)async 作为⼀个关键字放到函数的前⾯,⽤于表⽰函数是⼀个异步函数,该函数的执⾏不会阻塞后⾯代码的执⾏
4)await是等待,只能放到async函数⾥⾯,在后⾯放⼀个返回promise对象的表达式
5)async和await是为了解决⼤量复杂不易读的Promise异步的问题
1. async函数的改进
1)内置执⾏器,Generator 函数的执⾏必须依靠执⾏器,⽽ Aysnc 函数⾃带执⾏器,调⽤⽅式跟普通函数的调⽤⼀样
2)更好的语义,async 和 await 相较于 * 和 yield 更加语义化
3)更⼴的适⽤性,co 模块约定,yield 命令后⾯只能是 Thunk 函数或 Promise对象,⽽ async 函数的 await 命令后⾯则可以是Promise 或者 原始类型的值(Number,string,boolean,但这时等同于同步操作)
4)返回值是 Promise,async 函数返回值是 Promise 对象,⽐ Generator 函数返回的 Iterator 对象⽅便,可以直接使⽤ then() ⽅法进⾏调⽤
5)async⽅式,流程清晰,直观、语义明显,操作异步流程就如同操作同步流程, async 函数⾃带执⾏器,执⾏的时候⽆需⼿动加载。对于Promise的⽅式,如果处理流程复杂,整段代码将会充满then,不然很好的表⽰流程。对于Generator ⽅式,函数的执⾏需要依靠执⾏器,每次都需要通过 g.next() 的⽅式去执⾏
1. async和await的实例
1)async 作为⼀个关键字放到函数的前⾯,⽤于表⽰函数是⼀个异步函数,该函数的执⾏不会阻塞后
⾯代码的执⾏
实例代码:
async function timeout(){
return "hello word";
}
timeout();
// Promise __proto__: Promise [[PromiseStatus]]: "resolved" [[PromiseValue]]: "hello word"
//async返回的是 promise 对象
console.log(timeout());
// 我在后⾯,但是我是先执⾏的
console.log("我在后⾯,但是我是先执⾏的");
2)async声明的函数的返回本质上是⼀个Promise,async函数内部会返回⼀个Promise对象,then⽅法回调函数的参数
实例代码:
// hello world11
async function f1(){
return "hello world11";
};
f1().then((v)=>console.log(v));
3)await的本质是可以提供等同于”同步效果“的等待异步返回能⼒的语法糖,⽤await声明的Promise异步返回,必须“等待”到有返回值的时候,代码才继续执⾏下去
实例代码:
/* hello1
我是hello2
输出 hello1*/
const test = async()=>{
let message = "hello1";
let result = await message;
console.log(result);
console.log("我是hello2");
return result;
};
test().then(result =>{
console.log("输出",result);
});
4)async 函数内部的实现原理是resolved,如果函数内部抛出错误, 则会导致返回的 Promise 对象状态变为 reject 状态,promise 对象有⼀个catch ⽅法进⾏捕获,被 catch ⽅法回调函数接收到
实例代码:
async function timeout2(flag){
if(flag){
return "hello world";
}else{
throw "failed";
}
}
// 如果函数内部抛出错误, promise 对象有⼀个catch ⽅法进⾏捕获
timeout2(false).catch(err => {
console.log(err);
});
// hello word
// 调⽤solve() 返回promise 对象
console.log(timeout2(true));
// Uncaught (in promise) failed
// 调⽤ject() 返回promise 对象
console.log(timeout2(false));
5)async必须声明的是⼀个function,await就必须是在这个async声明的函数内部使⽤,必须是直系,作⽤域链不能隔代,在后⾯放⼀个返回promise对象的表达式
实例代码:
// 需求:2s后让数值乘以2
function doubleAfter(num){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(2*num)
},2000);
});
}
// 60
// 等待2s后,promis开始resolve,返回值
async function test(){
let result = await doubleAfter(30);
console.log(result);
}
test();
// 240
//等待6s后,promis开始resolve,返回值
async function test2(){
let first = await doubleAfter(30);
let second = await doubleAfter(40);
let third = await doubleAfter(50);
console.log(first+second+third);
}
test2();
6)函数的错误处理,当 async 函数中只要⼀个 await 出现 reject 状态,则后⾯的 await 都不会被执⾏,可以添加 try/catch 实例代码:
let a;
async function f5(){
ject("error");
a = await 1;
}
//f5().then(v=>console.log(a));
// try/catch 解决
// Uncaught (in promise) ReferenceError: error is not defined
at f6 (test13.html:124)
let a3;
async function f6(){
try{
ject("error");
}catch{
console.log(error);
}
a3 = await 123;
return a3;
}
f6().then((v)=>console.log(a3));
1. async/await的实战
1)需求分析:有两个延时函数,先延时1秒,在延迟2秒,再延时1秒,最后输出“完成”
2)实例代码:
// 延时函数
const setDelay = (millisecond) => {
return new Promise((resolve, reject)=>{
if (typeof millisecond != 'number') reject(new Error('参数必须是number类型'));
setTimeout(()=> {
resolve(`我延迟了${millisecond}毫秒后输出的`)
}, millisecond)
})
}
const setDelaySecond = (seconds) => {
return new Promise((resolve, reject)=>{
if (typeof seconds != 'number' || seconds > 10) reject(new Error('参数必须是number类型,并且⼩于等于10'));
setTimeout(()=> {
resolve(`我延迟了${seconds}秒后输出的,注意单位是秒`)
}, seconds * 1000)
})
}
/* 我延迟了${millisecond}毫秒后输出的
我延迟了${seconds}秒后输出的,注意单位是秒
我延迟了${millisecond}毫秒后输出的
完成*/
(async ()=>{
const result = await setDelay(1000);
console.log(result);
console.log(await setDelaySecond(2));
console.log(await setDelay(1000));
console.log('完成了');
})()
⼆、async和await的⾯试题总结
1. 谈谈对 async/await 的理解,async/await 的实现原理是什么?
1)async/await 就是 Generator 的语法糖,使得异步操作变得更加⽅便
2)async 函数就是将 Generator 函数的星号(*)替换成 async,将 yield 替换成await
3)async 是 Generator 的语法糖,这个糖体现在这⼏个⽅⾯:
await和async使用方法async函数内置执⾏器,函数调⽤之后,会⾃动执⾏,输出最后结果,⽽Generator需要调⽤next或者配合co模块使⽤
更好的语义,async和await,⽐起星号和yield,语义更清楚了,async表⽰函数⾥有异步操作,await表⽰紧跟在后⾯的表达式需要等待结果
更⼴的适⽤性,co模块约定,yield命令后⾯只能是 Thunk 函数或 Promise 对象,⽽async 函数的 await 命令后⾯,可以是Promise 对象和原始类型的值
返回值是Promise,async函数的返回值是 Promise 对象,Generator的返回值是 Iterator,Promise 对象使⽤起来更加⽅便4)async/await 函数的实现原理,就是将 Generator 函数和⾃动执⾏器,包装在⼀个函数⾥
5)实例代码分析:
function my_co(it) {
return new Promise((resolve, reject) => {
function next(data) {
try {
var { value, done } = it.next(data);
}catch(e){
return reject(e);
}
if (!done) {
//done为true,表⽰迭代完成
/
/value 不⼀定是 Promise,可能是⼀个普通值。使⽤ solve 进⾏包装。
next(val);
}, reject);
} else {
resolve(value);
}
}
next(); //执⾏⼀次next
});
}
function* test() {
yield new Promise((resolve, reject) => {
setTimeout(resolve, 100);
});
yield new Promise((resolve, reject) => {
// throw Error(1);
resolve(10)
});
yield 10;
return 1000;
}
my_co(test()).then(data => {
console.log(data); //输出1000
}).catch((err) => {
console.log('err: ', err);
});
1. 使⽤ async/await 需要注意什么?
1)await 命令后⾯的Promise对象,运⾏结果可能是 rejected,此时等同于 async 函数返回的 Promise 对象被reject。因此需要加上错误处理,可以给每个 await 后的 Promise 增加 catch ⽅法;也可以将 await 的代码放在 try…catch 中。
2)多个await命令后⾯的异步操作,如果不存在继发关系,最好让它们同时触发
实例代码:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论