摘要:首先我們來講這個棧在中,每當有函數被執行的時候都會在當前的執行堆棧中創建一個新的堆棧幀,并放到棧頂。因為是鏈式調用,所以代碼一直在同一個作用于中執行,也就是說當前的堆棧幀一直沒有被移出棧。
前言
前幾天在稀土上看到一篇面試的帖子,里面微信有一道題是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不是單單的在函數中執行,而是在對象鏈式調用中執行。因為是鏈式調用,所以代碼一直在同一個作用于中執行,也就是說當前的堆棧幀一直沒有被移出棧。上面的代碼中就是利用了這個特點解決了如何判斷對象調用結束的問題。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/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...
閱讀 546·2021-10-19 11:45
閱讀 1354·2021-09-30 09:48
閱讀 1470·2021-08-16 10:56
閱讀 733·2021-07-26 23:38
閱讀 3210·2019-08-30 13:15
閱讀 2594·2019-08-30 12:45
閱讀 1828·2019-08-29 12:14
閱讀 2074·2019-08-26 18:42