一、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 world11async 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// 调用Promise.resolve() 返回promise 对象console.log(timeout2(true));// Uncaught (in promise) failed// 调用Promise.reject() 返回promise 对象console.log(timeout2(false));

5)async必须声明的是一个function,await就必须是在这个async声明的函数内部使用,必须是直系,作用域链不能隔代,在后面放一个返回promise对象的表达式
实例代码:

 // 需求:2s后让数值乘以2function 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(){await Promise.reject("error");a = await 1;}//f5().then(v=>console.log(a));//  try/catch 解决// Uncaught (in promise) ReferenceError: error is not definedat f6 (test13.html:124)let a3;async function f6(){try{await Promise.reject("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 的语法糖,这个糖体现在这几个方面:
  • 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,可能是一个普通值。使用 Promise.resolve 进行包装。Promise.resolve(value).then(val => {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命令后面的异步操作,如果不存在继发关系,最好让它们同时触发
    实例代码:
//下面两种写法都可以同时触发
//法一
async function f1() {await Promise.all([new Promise((resolve) => {setTimeout(resolve, 600);}),new Promise((resolve) => {setTimeout(resolve, 600);})])
}
//法二
async function f2() {let fn1 = new Promise((resolve) => {setTimeout(resolve, 800);});let fn2 = new Promise((resolve) => {setTimeout(resolve, 800);})await fn1;await fn2;
}

3)await命令只能用在async函数之中,如果用在普通函数,会报错
4)async 函数可以保留运行堆栈
实例代码:

/
* 函数a内部运行了一个异步任务b()。当b()运行的时候,函数a()不会中断,而是继续执行。
* 等到b()运行结束,可能a()早就* 运行结束了,b()所在的上下文环境已经消失了。
* 如果b()或c()报错,错误堆栈将不包括a()。
*/
function b() {return new Promise((resolve, reject) => {setTimeout(resolve, 200)});
}
function c() {throw Error(10);
}
const a = () => {b().then(() => c());
};
a();
/**
* 改成async函数
*/
const m = async () => {await b();c();
};
m();
  • 本面试题为前端常考面试题,后续有机会继续完善。我是歌谣,一个沉迷于故事的讲述者。

    欢迎一起私信交流。

    “睡服“面试官系列之各系列目录汇总(建议学习收藏)

“约见”面试官系列之常见面试题第三十二篇之async和await(建议收藏)相关推荐

  1. “约见”面试官系列之常见面试题之第九十四篇之MVVM框架(建议收藏)

    目录 一句话总结:vm层(视图模型层)通过接口从后台m层(model层)请求数据,vm层继而和v(view层)实现数据的双向绑定. 1.我大前端应该不应该做复杂的数据处理的工作? 2.mvc和mvvm ...

  2. “约见”面试官系列之常见面试题之第九十二篇之created和mounted区别(建议收藏)

    beforeCreate 创建之前:已经完成了 初始化事件和生命周期 created 创建完成:已经完成了 初始化注册和响应 beforeMount 挂载之前:已经完成了模板渲染 mounted :挂 ...

  3. “约见”面试官系列之常见面试题之第五十七篇之强制类型转换(建议收藏)

    JS的类型转换,强制转换和隐式转换 JS的类型转换 1.强制转换 通过String(),Number(),Boolean()函数强制转换 var str=123;var str1='123';cons ...

  4. “约见”面试官系列之常见面试题之第五十一篇之CSS Sprites(建议收藏)

    CSS Sprites在国内很多人叫css精灵,是一种网页图片应用处理方式.它允许你将一个页面涉及到的所有零星图片都包含到一张大图中去,这样一来,当访问该页面时,载入的图片就不会像以前那样一幅一幅地慢 ...

  5. “约见”面试官系列之常见面试题第四十二篇之原型和原型链(建议收藏)

    原型和原型链的理解:(面试题) 原型:每个函数都有 prototype 属性,该属性指向原型对象:使用原型对象的好处是所有对象实例共享它所包含的属性和方法. 原型链:主要解决了继承的问题:每个对象都拥 ...

  6. “约见”面试官系列之常见面试题第三十九篇之异步更新队列-$nextTick(建议收藏)

    目录 一,前言 二,什么是异步更新队列 三,使用异步更新队列 四,结尾 一,前言 这一篇介绍有关异步更新队列的知识,通过异步更新队列的学习和研究能够更好的理解Vue的更新机制 二,什么是异步更新队列 ...

  7. “约见”面试官系列之常见面试题第三十八篇之js常见的继承方式(建议收藏)

    1.原型链继承 核心: 将父类的实例作为子类的原型 将构造函数的原型设置为另一个构造函数的实例对象,这样就可以继承另一个原型对象的所有属性和方法,可以继续往上,最终形成原型链 父类 // 定义一个动物 ...

  8. “约见”面试官系列之常见面试题第三十六篇之CSS常见兼容性问题及解决方案(建议收藏)

    CSS常见兼容性问题及解决方案: 1. 上下margin重合问题: 问题描述:相邻的margin-left和margin-right是不会重合的,但是相邻的块级元素margin-top 和margin ...

  9. “约见”面试官系列之常见面试题第三十五篇之轮循机制(建议收藏)

    目录 前言 任务队列 事件的概念 回调函数 事件轮询机制Event Loop: 结语 前言 有人称Event Loop为事件循环机制,而我更愿意将其解释为事件轮询机制,在之后的内容中你会感受到这一点的 ...

最新文章

  1. 这款NLP神器火了!关键词一键提取、结果高度可视化,堪称「小白进阶大神」的实用工具包 | 开源...
  2. od 追踪_裁判员行为规范【基本功】——追踪裁判违例宣判练习 /五秒违例
  3. python贴吧爬虫-Python爬虫——抓取贴吧帖子
  4. nyoj990蚂蚁感冒
  5. 用户体验改善案例_优化用户体验案例研究的五种方法
  6. P2801-教主的魔法【分块,二分】
  7. C++学习笔记56:异常处理
  8. ASCII码对照表(参考用)
  9. vue实现页面权限显示_Vue 实现前端权限控制
  10. 微信支付崩溃,却开启区块链数字货币大门?
  11. 将一个十进制转换为二进制,八进制,十六进制
  12. Linux磁盘设备文件(sda,sdb,sdc…)变化问题
  13. 芯片之路: 海思半导体前世今生
  14. 安卓android视频录制、另一部手机实时观看方案
  15. 【BP神经网络】西瓜分类和鸢尾花分类
  16. js获取当前指定的前几天的日期(如当前时间的前七天的日期)
  17. cad怎么设置线的粗细_CAD图纸线条粗细如何修改?CAD图纸线宽如何调整?
  18. 三维主成分图matlab,PCA主成分分析之三维演示(Matlab)
  19. 解决sublime text2字体显示模糊问题
  20. 随手记-记录一些技术点

热门文章

  1. Cogs 376. [IOI2002]任务安排(后效性DP)
  2. thread安全性(写的不错)
  3. mysql 分组后取每个组内最新的一条数据
  4. 第五——十三章的作业
  5. HTTPS下导出excel失败解决办法
  6. A+B for Matrices 及 C++ transform的用法
  7. 2数据库表增加一个字段_14个实用的数据库设计技巧!
  8. mysql联合索引顺序调整_MySQL 关于联合索引的字段顺序规则讨论
  9. sql获取某列出现频次最多的值_业务硬核SQL集锦
  10. mysql 列数据显示转成行数据显示_Mysql的列修改成行并显示数据的简单实现