目录

  • 异步编程样例
  • 样例解析
  • 浅谈Promise如何实现异步执行
  • 参考

1.异步编程样例

样例:

// 等待执行函数
function sleep(timeout) {
return new Promise((resolve) => {
setTimeout(resolve, timeout)
})
} // 异步函数
async function test() {
console.log('test start')
await sleep(1000)
console.log('test end')
} console.log('start')
test()
console.log('end')

执行结果:

start
test start
end
test end

2.样例解析

在样例代码中,test异步函数使用了asyncawait语法,这是ES2017里面的异步编程规范。而为了在较低版本的浏览器或Node支持这种语法,其中一种解决方案是将其转化为Generator函数和Promise来实现。换句话说,任何的asyncawait实现的异步函数,都可以替换成Generator函数和Promise实现。

第一步:先将asyncawait语法替换为相应的Generator 函数,如下

// 代码结构完全一致,只是替换了对应关键字
function *test() {
console.log('test start')
yield sleep(1000)
console.log('test end')
}

第二步:为了执行Generator 函数,使用Promise实现一个自动执行器函数 spawn

function spawn(genF) {
return new Promise(function(resolve, reject) {
const gen = genF();
function step(nextF) {
let next;
try {
next = nextF();
} catch(e) {
return reject(e);
}
if(next.done) {
return resolve(next.value);
}
Promise.resolve(next.value).then(function(v) {
step(function() { return gen.next(v); });
}, function(e) {
step(function() { return gen.throw(e); });
});
}
step(function() { return gen.next(undefined); });
});
}

第三步:将相应的Generator 函数和自动执行器函数相结合,即可得最终的等价代码

function asyncTest() {
spawn(test)
} console.log('start')
asyncTest()
console.log('end')

第四步:执行结果,与原来的一致

start
test start
end
test end

第五步:分析asyncTest函数执行过程

  1. 执行到 spawn(test),进入spawn函数中,创建一个Promise并返回。
  2. 执行到 const gen = genF(),获取一个状态机。(Generator 函数是一个状态机,封装了多个内部状态。)
  3. 执行到 step(function() { return gen.next(undefined); }), 进入step 函数中。
  4. 执行到next = nextF()next等于gen.next(undefined)的返回结果。
    • gen.next(undefined)开始执行,状态机第一次调用,直到遇到第一个yield表达式为止,即yield sleep(1000),此时控制台先输出"test start",并且返回第一个状态{ value: reuslt, done: false }, 而 reuslt等于sleep(1000)返回的结果,其是一个Promise。
  5. 执行到if(next.done) ,此时第一个状态的donefalse,所以不执行if语句里面,继续往下执行。
  6. 执行到Promise.resolve(next.value),由于第一个状态的value是一个Promise,所以直接返回其本身,也就相当于执行sleep(1000).then(...),sleep函数异步等待1秒后,resolve接受的值为undefined,继续执行then方法。
  7. 执行到 step(function() { return gen.next(v); }),此时vundefined,再次进入step 函数中。
  8. 再次执行到next = nextF()next等于gen.next(undefined)的返回结果。
    • gen.next(undefined)再次执行时,状态机第二次调用,此时Generator函数已经执行完毕,此时控制台先输出"test end",并且返回最后的状态{ value: undefined, done: true }
  9. 执行到if(next.done) ,此时第一个状态的donetrue,所以执行if语句里面。
  10. 执行到return resolve(next.value),此时最初的Promise成功执行。
  11. 至此asyncTest函数执行结束。

3.浅谈Promise如何实现异步执行

从上述样例解析中可以看出,我们是用Promise来实现代码的异步执行,那Promise的内部是如何实现异步执行的呢?

通过查看Promise源码实现,发现其异步执行是通过asap这个库来实现的。

asapas soon as possible的简称,在Node和浏览器环境下,能将回调函数以高优先级任务来执行(下一个事件循环之前),即把任务放在微任务队列中执行。

宏任务(macro-task)和微任务(micro-task)表示异步任务的两种分类。在挂起任务时,JS 引擎会将所有任务按照类别分到这两个队列中,首先在 macrotask 的队列(这个队列也被叫做 task queue)中取出第一个任务,执行完毕后取出 microtask 队列中的所有任务顺序执行;之后再取 macrotask 任务,周而复始,直至两个队列的任务都取完。

用法:

asap(function () {
// ...
});

补充说明:这里提及的Promise源码并不是Node和浏览器的原生实现,是一个第三方库,仅以此为参考。

4.参考

ECMAScript 6 入门 - async 函数

【翻译】Promises/A+规范

Promise - Bare bones Promises/A+ implementation

async和await是如何实现异步编程?的更多相关文章

  1. .NET4.5新特性async和await修饰符实现异步编程

    开篇 每一个版本的.net都会引入一些新的特性,这些特性方便开发人员能够快速实现一些功能.虽然.net版本一直在更新,但是新版本对旧版本的程序都是兼容的,在这一点上微软做的还是非常好的.每次学一个新内 ...

  2. python教程:使用 async 和 await 协程进行并发编程

    python 一直在进行并发编程的优化, 比较熟知的是使用 thread 模块多线程和 multiprocessing 多进程,后来慢慢引入基于 yield 关键字的协程. 而近几个版本,python ...

  3. [.NET] 利用 async & await 的异步编程

    利用 async & await 的异步编程 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/5922573.html  目录 异步编程的简介 异 ...

  4. 使用 Async 和 Await 的异步编程(C# 和 Visual Basic)[msdn.microsoft.com]

    看到Microsoft官方一篇关于异步编程的文章,感觉挺好,不敢独享,分享给大家. 原文地址:https://msdn.microsoft.com/zh-cn/library/hh191443.asp ...

  5. 【转】【C#】C# 5.0 新特性——Async和Await使异步编程更简单

    一.引言 在之前的C#基础知识系列文章中只介绍了从C#1.0到C#4.0中主要的特性,然而.NET 4.5 的推出,对于C#又有了新特性的增加--就是C#5.0中async和await两个关键字,这两 ...

  6. .NET4.5 异步编程 async和await

    msdn介绍:https://msdn.microsoft.com/zh-cn/library/hh191443.aspx 其实很简单,标记了async的方法为异步方法,从方法的左大括号开始同步执行, ...

  7. 使用 Async 和 Await 的异步编程

    来自:http://msdn.microsoft.com/library/vstudio/hh191443   异步对可能起阻止作用的活动(例如,应用程序访问 Web 时)至关重要. 对 Web 资源 ...

  8. .Net 4.5 异步编程初试(async和await)

    .Net 4.5 异步编程初试(async和await) 前言 最近自己在研究Asp.Net Web API.在看到通过客户端来调用Web API的时候,看到了其中的异步编程,由于自己之前没有接触过, ...

  9. 转:[你必须知道的异步编程]C# 5.0 新特性——Async和Await使异步编程更简单

    本专题概要: 引言 同步代码存在的问题 传统的异步编程改善程序的响应 C# 5.0 提供的async和await使异步编程更简单  async和await关键字剖析 小结 一.引言 在之前的C#基础知 ...

随机推荐

  1. DUBBO 面试灵魂18问

    一.Dubbo 是什么 dubbo 是一个分布式框架,是一个远程服务调用的分布式框架,其核心部分包含: 1)集群容错: 提供基于接口方法的透明远程过程调用,包含多协议支持,以及软负债均衡.失败容错.地 ...

  2. 大型Java进阶专题(三) 软件架构设计原则(下)

    前言 ​ 今天开始我们专题的第二课了,本章节继续分享软件架构设计原则的下篇,将介绍:接口隔离原则.迪米特原则.里氏替换原则和合成复用原则.本章节参考资料书籍<Spring 5核心原理>中的 ...

  3. 分享一次C#调用Delphi编写Dll程序

    1.前言: 最近接手了一个项目需要和Delphi语言编写的一个系统进行一些接口的对接,数据在传输过程中采用Des加密方式,因为Delphi 平台的加密方式和C#平台的加密方式不互通,所以采用的方式是C ...

  4. Community Cloud零基础学习(四)Builder创建自定义的布局

    前几篇讲了Community Cloud权限配置等信息,但是没有太讲过 Community如何进行配置layout,本篇主要描述使用Builder去进行符合需求的Community Layout的构建 ...

  5. JavaScript规范----DOM操作

    一般通过JS代码操作DOM结构,会触发浏览器进行页面渲染.所以要尽量减少DOM操作,避免频繁的页面渲染对性能造成影响. 如有以下场景:程序执行ajax请求,并根据请求结果动态添加列表项.常见的做法是循 ...

  6. burpsuit之Spider、Scanner、Intruder模块

    1.spider模块 1.spider模块介绍 被动爬网:(被动爬网获得的链接是手动爬网的时候返回页面的信息中分析发现超链接) 对于爬网的时候遇到HTML表单如何操作: 需要表单身份认证时如何操作(默 ...

  7. Hadoop集群搭建(四)~centos6.8关闭防火墙

    一.centos关闭防火墙 1,关闭防火墙.service iptables stop 2,关闭防火墙开机自启.chkconfig iptables off 3,查看防火墙状态.service ipt ...

  8. 干货来啦。Flask框架看这一篇就够了,关注不迷路,Jeff带你看源码。开发技术时时更新

    目录 一.初识Flask 1.1 什么是flask? 1.2 为什么要有flask? 二.Flask快速启动 三.Flask四剑客 三.flask的配置文件 可以配置的属性 四.flask路由 4.1 ...

  9. cmdb采集数据的版本

    在局部配置文件中配置MODE=' agent',或者MODE=‘ssh’,或者MODE=‘’saltstack ',  实现只需要修改这个配置,就会使用对应的方案进行采集数据 第一种版本: 启动文件中 ...

  10. [树的度数] Christmas Spruce

    Consider a rooted tree. A rooted tree has one special vertex called the root. All edges are directed ...