摘要:首先我们来讲这个栈在中,每当有函数被执行的时候都会在当前的执行堆栈中创建一个新的堆栈帧,并放到栈顶。因为是链式调用,所以代码一直在同一个作用于中执行,也就是说当前的堆栈帧一直没有被移出栈。
前言
前几天在稀土上看到一篇面试的帖子,里面微信有一道题是lazyman的实现,具体要做的事情就是
LazyMan(“Hank”) //Hi! This is Hank! LazyMan(“Hank”).sleep(10).eat(“dinner”) // Hi! This is Hank! // 等待10秒.. // Wake up after 10 // Eat dinner~ LazyMan(“Hank”).eat(“dinner”).eat(“supper”) // Hi This is Hank! // Eat dinner~ // Eat supper~ LazyMan(“Hank”).sleepFirst(5).eat(“supper”) // 等待5秒 // Wake up after 5 // Hi This is Hank! // Eat supper
这道题考察的肯定不是实现这个函数的能力问题,应该是流程控制的问题。解决思路应该是将所有的人如都存放到一个数组中,并在所有的方法执行完之后一次性的输出,实现的代码如下:
function _LazyMan(name) { this.tasks = []; var self = this; var fn =(function(n){ var name = n; return function(){ console.log("Hi! This is " + name + "!"); self.next(); } })(name); this.tasks.push(fn); setTimeout(function(){ self.next(); }, 0); // 在下一个事件循环启动任务 } /* 事件调度函数 */ _LazyMan.prototype.next = function() { var fn = this.tasks.shift(); fn && fn(); } _LazyMan.prototype.eat = function(name) { var self = this; var fn =(function(name){ return function(){ console.log("Eat " + name + "~"); self.next() } })(name); this.tasks.push(fn); return this; // 实现链式调用 } _LazyMan.prototype.sleep = function(time) { var self = this; var fn = (function(time){ return function() { setTimeout(function(){ console.log("Wake up after " + time + "s!"); self.next(); }, time * 1000); } })(time); this.tasks.push(fn); return this; } _LazyMan.prototype.sleepFirst = function(time) { var self = this; var fn = (function(time) { return function() { setTimeout(function() { console.log("Wake up after " + time + "s!"); self.next(); }, time * 1000); } })(time); this.tasks.unshift(fn); return this; } /* 封装 */ function LazyMan(name){ return new _LazyMan(name); }
我自己在思考解决方法的时候最让我困惑的就是如果判断Lazyman对象的方法被调用结束了?我甚至为了这个问题坐过了站。。。后来当我看到这段代码的时候,发现一个简单的setTimeout就解决了这个问题,为什么呢???
并发模型与Event Loop这张图是MDN对Event Loop的解释,这张图上分为三个部分,分别是队列、栈、和堆。我们在理解lazyman的过程中需要知道的就是队列和栈。首先我们来讲这个栈:
在js中,每当有函数被执行的时候都会在当前的执行堆栈中创建一个新的堆栈帧,并放到栈顶。这个堆栈帧中包含当前执行的函数的参数和局部变量。(有没有感觉很熟悉,没错,这就是我们理解作用域链的时候的那个栈)而当我们的函数执行完之后,这个堆栈帧就会从当前栈中移除。
队列就是JS中用来处理异步事件的队列,每当有新的异步事件发生,就会添加一个新的消息到队列的尾部。当之前提到的栈为空时,JS就会来处理队列中的消息。
举个例子来说就是:
var a = function() { setTimeout(function(){console.log(1)},0) } var b = function(){ a() console.log(2) } // 2 // 1
这里需要注意的有
就算你不在函数中使用setTimeout,而是在全局环境中使用,setTimeout也是在正常的同步代码执行完之后执行,这是因为还有宿主环境在。
setTimeOut是经过一段时间之后直接向队列中加入一个消息,而普通的http请求是等到有返回结果了才会将消息加入到队列中。
普通的异步事件如果没有事件监听器的话是不会操作队列的,消息是直接被忽视掉。
Lazyman中的setTimeoutLazyman中的`setTimeout不是单单的在函数中执行,而是在对象链式调用中执行。因为是链式调用,所以代码一直在同一个作用于中执行,也就是说当前的堆栈帧一直没有被移出栈。上面的代码中就是利用了这个特点解决了如何判断对象调用结束的问题。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/81319.html
摘要:计算数组的极值微信面试题获取元素的最终前端掘金一题目用代码求出页面上一个元素的最终的,不考虑浏览器,不考虑元素情况。 Excuse me?这个前端面试在搞事! - 前端 - 掘金金三银四搞事季,前端这个近年的热门领域,搞事气氛特别强烈,我朋友小伟最近就在疯狂面试,遇到了许多有趣的面试官,有趣的面试题,我来帮这个搞事 boy 转述一下。 以下是我一个朋友的故事,真的不是我。 ... ja...
摘要:最后画几张粗糙的图,简单描述一下这个执行的过程因为是链式调用,所以在链上的都会入栈然后执行,额,执行栈少画了和。。。 前言:昨天在群里讨(jin)论(chui)技(niu)术(pi),有位老铁发了一道他面的某公司面试题,顺手保存了。今早花了一点时间把这题做了出来,发现挺有意思的,决定在今天认真工(hua)作(shui)前,与大家分享我的解题方案和思考过程。 题目如下(可以自己先思考一会...
摘要:关于的和以上是关于与的所有文件指令分析里面意思运行的时候执行的是文件,运行的时候执行的是文件。前端开发过程中需要使用到后台的的话,可以通过配置来将相应的后台请求代理到专用的服务器。和这三个文件就简单设置了环境变量而已,没什么特别的。 关于vue的npm run dev和npm run build├─build│ ├─build.js│ ├─check-versions.js│ ...
摘要:前言笔者昨天在做某公司的线上笔试题的时候遇到了最后一道关于如何实现的试题,题目如下实现一个,可以按照以下方式调用输出输出等待秒输出输出等待秒以此类推。 前言 笔者昨天在做某公司的线上笔试题的时候遇到了最后一道关于如何实现LazyMan的试题,题目如下 实现一个LazyMan,可以按照以下方式调用:LazyMan(Hank)输出:Hi! This is Hank!LazyMan(Hank...
摘要:能不能支持数据丢失啊可以的,参考我们之前说的那个数据零丢失方案其实一个肯定是很复杂的,其实这是个开放题,就是看看你有没有从架构角度整体构思和设计的思维以及能力。其实回答这类问题,说白了,起码不求你看过那技术的源码,起码你大概知道那个技术的基本原理,核心组成部分,基本架构构成,然后参照一些开源的技术把一个系统设计出来的思路说一下就好 比如说这个消息队列系统,我们来从以下几个角度来考虑一下 (1...
阅读 512·2021-10-19 11:45
阅读 1290·2021-09-30 09:48
阅读 1426·2021-08-16 10:56
阅读 693·2021-07-26 23:38
阅读 3177·2019-08-30 13:15
阅读 2552·2019-08-30 12:45
阅读 1768·2019-08-29 12:14
阅读 1969·2019-08-26 18:42