浅谈Generator和Promise原理及实现
Generator
熟悉ES6语法的同学们肯定对Generator(生成器)函数不陌生,这是一个化异步为同步的利器。
栗子:
function* abc() {let count = 0;while(true) {let msg = yield ++count;console.log(msg);}
}let iter = abc();
console.log(iter.next().value);
// 1
console.log(iter.next('abc').value);
// 'abc'
// 2
首先,我们先简单回顾一下JS的运行规则:
- JS是单线程的,只有一个主线程
- 函数内的代码从上到下顺序执行,遇到被调用的函数先进入被调用函数执行,待完成后继续执行
- 遇到异步事件,浏览器另开一个线程,主线程继续执行,待结果返回后,执行回调函数
那么,Generator函数是如何进行异步化为同步操作的呢?
实质上很简单,* 和 yield 是一个标识符,在浏览器进行软编译的时候,遇到这两个符号,自动进行了代码转换:
// 异步函数
function asy() {$.ajax({url: 'test.txt',dataType: 'text',success() {console.log("我是异步代码");}})
}function* gener() {let asy = yield asy();yield console.log("我是同步代码");
}
let it = gener().next();
it.then(function() {it.next();
})
// 我是异步代码
// 我是同步代码
// 浏览器编译之后
function gener() {// let asy = yield asy(); 替换为$.ajax({url: 'test.txt',dataType: 'text',success() {console.log("我是异步代码");// next 之后执行以下console.log("我是同步代码");}})// yield console.log("我是同步代码");
}
整个过程类似于,浏览器遇到标识符 * 之后,就明白这个函数是生成器函数,一旦遇到 yield 标识符,就会将以后的函数放入此异步函数之内,待异步返回结果后再进行执行。
更深一步,从内存上来讲:
普通函数在被调用时,JS 引擎会创建一个栈帧,在里面准备好局部变量、函数参数、临时值、代码执行的位置(也就是说这个函数的第一行对应到代码区里的第几行机器码),在当前栈帧里设置好返回位置,然后将新帧压入栈顶。待函数执行结束后,这个栈帧将被弹出栈然后销毁,返回值会被传给上一个栈帧。
当执行到 yield 语句时,Generator 的栈帧同样会被弹出栈外,但Generator在这里耍了个花招——它在堆里保存了栈帧的引用(或拷贝)!这样当 it.next 方法被调用时,JS引擎便不会重新创建一个栈帧,而是把堆里的栈帧直接入栈。因为栈帧里保存了函数执行所需的全部上下文以及当前执行的位置,所以当这一切都被恢复如初之时,就好像程序从原本暂停的地方继续向前执行了。
而因为每次 yield 和 it.next 都对应一次出栈和入栈,所以可以直接利用已有的栈机制,实现值的传出和传入。
至此,Generator 的魔力已经揭开。
Promise
Promise的用法大家应该都很熟悉:
let pr = new Promise(function(resolve, reject) {setTimeout(function() {resolve("成功执行啦");}, 2000)
})
pr.then(function(data) {console.log(data); // 成功执行啦
})
那么 Promise 是如何实现异步加载的呢?
Promise 并没有大家想的那么神秘,其本质就是一个状态机。
想要实现一个土生土长的 Promise 其实很简单,状态机,我们需要几个参数:
- __success_res 用来存储成功时的参数
- __error_res 用来存储失败时的参数
- __status 用来存储状态
- __watchList 用来存储执行队列
下面就手动实现一个 Promise
class Promise1 {constructor(fn) {// 执行队列this.__watchList = [];// 成功结果this.__success_res = null;// 失败结果this.__error_res = null;// 状态this.__status = "";fn((...args) => {// 保存成功数据this.__success_res = args;// 状态改为成功this.__status = "success";// 若为异步则回头执行then成功方法this.__watchList.forEach(element => {element.fn1(...args);});}, (...args) => {// 保存失败数据this.__error_res = args;// 状态改为失败this.__status = "error";// 若为异步则回头执行then失败方法this.__watchList.forEach(element => {element.fn2(...args);});});}// then 函数then(fn1, fn2) {if (this.__status === "success") {fn1(...this.__success_res);} else if (this.__status === "error") {fn2(...this.__error_res);} else {this.__watchList.push({fn1,fn2})}}
}
这样就简单实现了 Promise 的功能,在使用上和JS的 Promise 并无其他区别,若想实现 Promise.all 方法,则只需要进行小小的迭代:
Promise1.all = function(arr) {// 存放结果集let result = [];return Promise1(function(resolve, reject) {let i = 0;// 进行迭代执行function next() {arr[i].then(function(res) {// 存放每个方法的返回值result.push(res);i++;// 若全部执行完if (i === result.length) {// 执行then回调resolve(result);} else {// 继续迭代next();}}, reject)}})
}
至此,Generator 和 Promise 都已解析完成。
浅谈Generator和Promise原理及实现相关推荐
- 浅谈Rem 及其转换原理
浅谈Rem 及其转换原理 今天有小伙伴问了我Rem的转换原理,那我就写篇博客记录一下吧! rem 是 CSS3 新增的相对长度单位,是指相对于元素 html 的 font-size 计算值 的大小. ...
- 浅谈人工智能的工作原理
众所周知人工智能现在快速发展,并且为众人所熟知,不仅如此,人工智能也在各行各业中广泛使用.那么人工智能的工作原理是什么呢? 浅谈人工智能的工作原理 人类智能由三个部分构成(还有些其他生物学和科学现象也 ...
- 动态磅是怎么原理_浅谈动态地磅的原理及未来发展方向
浅谈动态地磅的原理及未来发展方向: 文章介绍了动态地磅的结构和工作原理,针对动态地磅的分类做了全面的概述,分别对不同的动态地磅做了对比及详细的阐述,说明选择和使用动态地磅器的注意事项,凸显了轴组式动态 ...
- 浅谈 git 底层工作原理
浅谈 git 底层工作原理 系统复习到这里也快差不多了,大概就剩下两三个 sections,这里学习一下 git 的 hashing 和对象. 当然,跳过问题也不大. config 文件 这里还是会用 ...
- 伺服驱动器生产文件_浅谈伺服驱动器的工作原理
原标题:浅谈伺服驱动器的工作原理 目前,主流的伺服驱动器均采用数字信号处理器(DSP)作为控制核心,可以实现比较复杂的控制算法,实现数字化.网络化和智能化.功率器件普遍采用以智能功率模块(IPM)为核 ...
- 深入浅谈,CPU设计原理
首先,声明这是一篇转载文,这篇文章是,从卡饭论坛 看到的一篇文章<深入浅谈,CPU设计原理>,是一篇连载,文章,卡饭论坛,是我高中的时候,经常去的论坛,里面有很多好的文章,推荐给大家.也许 ...
- 浅谈代理服务器工作的原理
浅谈代理服务器工作的原理 (1) 代理服务原理 代理服务器有很多种,大体来说有http,ftp,socks代理三种,其中又分透明代理和不透明代理.其中透明代理一般是网关,是硬件.所以这里讨论不透明代理 ...
- 浅谈《微信抢红包原理》
现在很多人手机可能都安装了抢红包软件,为了过年抢红包不错过,当然会下载来用用,其实,现在的抢红包软件,基本都是通过监听通知栏消息"[微信红包]"字样,作为识别是红包的依据的,可能大 ...
- 浅谈elasticsearch的分词原理
这篇文章主要是来浅谈一下elasticsearch的分词原理,让各位同学对分词不再陌生~ 废话不多说,我们直接上干货 前言一 我们创建一个文档 PUT test/_doc/1 {"msg&q ...
最新文章
- php在dw中设置按钮圆角,Dreamweaver怎么用CSS制作圆角按钮?
- Pytorch之深入理解torch.nn.Parameter()
- CloudStack管理员文档 - 虚拟机
- Java Spring singleton bean的创建源代码
- 隐藏apache版本号的方法
- 虚拟化简化数据中心管理
- NOIP2002题目汇总
- 第五章---引入VIP后的数据库架构
- TokenInsight:反映区块链行业整体表现的TI指数较昨日同期下降3.29%
- JSON 解析之 GSON
- 基于高德地图api的热力图配置及显示调优
- Base64转换成图片
- 教师计算机考核有啥用,教师计算机使用管理制度和考核方案
- 计算机开启后显示器黑屏,电脑打开后显示器黑屏怎么办
- 人工智能--技术发展史
- K8S pod 时区设置
- 【Matlab】希腊字母
- TCP协议——三次握手
- Excel数据透视表只能求和运算?快来学习求差运算小技巧
- C语言过时了?扯淡!