前言

async await 语法是 ES7出现的,是基于ES6的 promise和generator实现的

generator函数

在之前我专门讲个generator的使用与原理实现,大家没了解过的可以先看那个手写generator核心原理,再也不怕面试官问我generator原理

这里就不再赘述generator,专门的文章讲专门的内容。

await在等待什么

我们先看看下面这代码,这是async await的最简单使用,await后面返回的是一个Promise对象:

async function getResult() {
await new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
console.log(1);
}, 1000);
})
} getResult()

但不知你有没有想过一个问题,为什么会等到返回的promise的对象的状态为非pending的时候才会继续往下执行,也就是resolve执行之后,才会继续执行,就像下面的代码一样

async function getResult() {
await new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
console.log(1);
}, 1000);
})
console.log(2);
} getResult()

可以看到运行结果是先打印了1,再打印2了,也就是说明在返回的promise对象没执行resolve()前,就一直在await,等它执行。然后再执行下面的程序,那这个是怎么实现的呢?

原理实现

我们看一下下面的代码,输出顺序是什么?

async function getResult() {
await new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
console.log(1);
}, 1000);
}) await new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2);
console.log(2);
}, 500);
}) await new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3);
console.log(3);
}, 100);
}) } getResult()

没错是 1,2,3.

那用generator函数专门来实现这个效果呢

我一开始这样来实现:

function* getResult(params) {

    yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
console.log(1);
}, 1000);
}) yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2);
console.log(2);
}, 500);
}) yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3);
console.log(3);
}, 100);
})
}
const gen = getResult() gen.next();
gen.next();
gen.next();

但是发现打印顺序是 3,2,1.明显不对。

这里的问题主要是三个 new Promise几乎是同一时刻执行了。才会出现这种问题,所以需要等第一个promise执行完resolve之再执行下一个,所以要这么实现

function* getResult(params) {

    yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
console.log(1);
}, 1000);
}) yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2);
console.log(2);
}, 500);
}) yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3);
console.log(3);
}, 100);
})
}
const gen = getResult() gen.next().value.then(() => {
gen.next().value.then(() => {
gen.next();
});
});

可以看到这样就打印正常了。

特别 需要解释下。gen.next().value 就是返回的promise对象,不理解的可以看看文首介绍的那篇generator的 文章。手写generator核心原理,再也不怕面试官问我generator原理

优化

但是呢,总不能有多少个await,就要自己写多少个嵌套吧,所以还是需要封装一个函数,显然,递归实现最简单

function* getResult(params) {

    yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
console.log(1);
}, 1000);
}) yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2);
console.log(2);
}, 500);
}) yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3);
console.log(3);
}, 100);
})
}
const gen = getResult() function co(g) {
g.next().value.then(()=>{
co(g)
})
} co(gen)

再来看看打印结果

可以发现成功执行了,但是为什么报错了?

这是因为generator方法会返回四次,最后一次的value是undefined。

而实际上返回第三次就表示已经返回done,代表结束了,所以,我们需要判断是否是已经done了,不再让它继续递归

所以可以改成这样

function* getResult(params) {

    yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
console.log(1);
}, 1000);
}) yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2);
console.log(2);
}, 500);
}) yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3);
console.log(3);
}, 100);
})
}
const gen = getResult() function co(g) {
const nextObj = g.next();
if (nextObj.done) {
return;
}
nextObj.value.then(()=>{
co(g)
})
} co(gen)

可以看到这样就实现了。

总结给大家推荐一个实用面试题库

 1、前端面试题库 (面试必备)            推荐:★★★★★

地址:前端面试题库

2、前端技术导航大全      推荐:★★★★★

地址:前端技术导航大全

3、开发者颜色值转换工具   推荐:★★★★★

地址 :开发者颜色值转换工具

【面试题】手写async await核心原理,再也不怕面试官问我async await原理的更多相关文章

  1. 看完这一篇,再也不怕面试官问到IntentService的原理

    IntentService是什么 在内部封装了 Handler.消息队列的一个Service子类,适合在后台执行一系列串行依次执行的耗时异步任务,方便了我们的日常coding(普通的Service则是 ...

  2. [每日一题]面试官问:Async/Await 如何通过同步的方式实现异步?

    关注「松宝写代码」,精选好文,每日一题 ​时间永远是自己的 每分每秒也都是为自己的将来铺垫和增值 作者:saucxs | songEagle 一.前言 2020.12.23 日刚立的 flag,每日一 ...

  3. 手写webpack核心原理,再也不怕面试官问我webpack原理

    手写webpack核心原理 目录 手写webpack核心原理 一.核心打包原理 1.1 打包的主要流程如下 1.2 具体细节 二.基本准备工作 三.获取模块内容 四.分析模块 五.收集依赖 六.ES6 ...

  4. 深度剖析Java的volatile实现原理,再也不怕面试官问了

    上篇文章我们讲了synchronized的用法和实现原理,我们总爱说synchronized是重量级锁,volatile是轻量级锁.为什么volatile是轻量级锁,体现在哪些方面?以及volatil ...

  5. 如何完美回答面试官问的Mybatis初始化原理!!!

    前言 对于任何框架而言,在使用前都要进行一系列的初始化,MyBatis也不例外.本章将通过以下几点详细介绍MyBatis的初始化过程. MyBatis的初始化做了什么 MyBatis基于XML配置文件 ...

  6. [每日一题]面试官问:for in和for of 的区别和原理?

    关注「松宝写代码」,精选好文,每日一题 ​时间永远是自己的 每分每秒也都是为自己的将来铺垫和增值 作者:saucxs | songEagle 一.前言 2020.12.23 日刚立的 flag,每日一 ...

  7. 「每日一题」有人上次在dy面试,面试官问我:vue数据绑定的实现原理。你说我该如何回答?

    关注「松宝写代码」,精选好文,每日一题 ​时间永远是自己的 每分每秒也都是为自己的将来铺垫和增值 作者:saucxs | songEagle 来源:原创 一.前言 文章首发在「松宝写代码」 2020. ...

  8. JAVA面试题 手写ArrayList的实现,在笔试中过关斩将?

    面试官Q1:可以手写一个ArrayList的简单实现吗? 我们都知道ArrayList是基于数组实现,如果让你实现JDK源码ArrayList中add().remove().get()方法,你知道如何 ...

  9. 常见python面试题-手写代码系列

    1.如何反向迭代一个序列 #如果是一个list,最快的方法使用reversetempList = [1,2,3,4]tempList.reverse()for x in tempList:    pr ...

  10. (手写)mybatis 核心配置文件和接口不在同一包下的解决方案

    smart-sh-mybatis项目 app.xml文件中此处配置为: <!-- 从整合包里找,org.mybatis:mybatis-spring:1.2.4 --> <!-- s ...

随机推荐

  1. [LeetCode]二进制求和

    题目 代码 class Solution { public: string addBinary(string a, string b) { int lenA = a.length(); int len ...

  2. Mac上优秀的虚拟机软件推荐 PD Parallels Desktop 18.1.1

    APPERK 软件信息 软件名称 ParallelsDesktop 版本号 18.1.1 软件类型 官网版 + 商业版 安装包大小 390MB 语言 中文 系统支持 macOS11及以上(M芯片原生) ...

  3. python3进行3des的加密解密

    #秘钥长度正常24位,16位补齐第一个八位 import pyDes import base64 print('=======key1=======') keys='1234567890123456' ...

  4. SpringCloud————>了解什么是微服务技术

    SpringCloud是Spring为微服务架构思想做的一个一站式实现.从某种程度是可以简单的理解为,微服务是一个概念.一个项目开发的架构思想.SpringCloud是微服务架构的一种java实现. ...

  5. 如何在es中查询null值

    目录 1.背景 2.需求 3.准备数据 3.1 创建mapping 3.2 插入数据 4.查询 name字段为null的数据 5.查询address不存在或值直接为null的数据 6.参考链接 1.背 ...

  6. Node.js学习笔记----day05(在Node中操作MySQL)

    认真学习,认真记录,每天都要有进步呀!!! 加油叭!!! 一.安装 初始化项目 安装mysql(这里的mysql是node用来操作mysql的一个第三方包,包的名字就叫mysql) 安装mysql包的 ...

  7. KStudio-Java程序连接KingbaseES数据库异常

    错误信息: --KStudio客户端工具错误信息 The conncetion attempt failed.Reason:connect time out --Java应用程序控制台日志 Cause ...

  8. Task记录1.CancellationToken 取消Task任务的操作

    //1.创建取消令牌数据 CancellationTokenSource tokenSource = new CancellationTokenSource(); //2.创建取消令牌 Cancell ...

  9. FAQ 关于allure和pycharm的运行模式

    关于allure和pycharm的运行模式 案例 新建一个项目allure_mode 新建一个python代码test_allure_001.py 代码如下 import pytest, os def ...

  10. CentOS7 RPM方式安装JDK

    1.下载jdk rpm Java Downloads | Oracle 中国 https://www.oracle.com/cn/java/technologies/downloads/#jdk19- ...