LazyMan實現(xiàn)— promise 雜談

簡略圖(徒手畫略丑)

閑逛的時候發(fā)現(xiàn)了一道LazyMan的前端面試題增热,感覺挺有意思稠氮,下面給出本人的結(jié)題思路洽瞬,以及關(guān)于promise的一些基礎(chǔ)

promise基礎(chǔ)

一棵帽、異步:現(xiàn)在與將來

1. 事件循環(huán)
<!--eventLoop 是一個用作隊列的數(shù)組-->
<!--(先進(jìn)先出)-->
var eventLoop = [];
var event;

<!--"永遠(yuǎn)"執(zhí)行-->
while(true){
    <!--一次 tick-->
    if(eventLoop.length>0){
        <!--拿到隊列中的下一個事件-->
        event = eventLoop.shift();
        <!--現(xiàn)在妹卿,執(zhí)行下一個事件-->
        try{
            event();
        }
        catch(err){
            reportError(err);
        }
    }
}
一定要清楚旺矾,setTimeout(..) 并沒有把你的回調(diào)函數(shù)掛在事件循環(huán)隊列中。它所做的是設(shè)定一個定時器夺克。當(dāng)定時器到時后箕宙,環(huán)境會把你的回調(diào)函數(shù)放在事件循環(huán)中,這樣铺纽,在未來某個時刻的tick會摘下并執(zhí)行這個回調(diào)函數(shù)

程序通常分成了很多小塊柬帕,在事件循環(huán)隊列中一個接一個地執(zhí)行,嚴(yán)格的說,和你的程序不直接相關(guān)的其他事件也可能會插入到隊列中陷寝。

2. js中的函數(shù)具有原子性
3. Promise

3.1 Promise 至多只能有一個決議值(完成或拒絕)

如果你沒有用任何值顯式?jīng)Q議锅很,那么這個值就是undefined,這是javaScript常見的處理方式。但是不管這個值是什么凤跑,無論當(dāng)前或者未來爆安,它都會被傳給所有注冊的(且適當(dāng)?shù)耐瓿苫蚓芙^)的回調(diào)。
還有一點(diǎn)需要清楚:如果使用多個參數(shù)調(diào)用resolve(..) 或者reject(..),第一個參數(shù)之后的所有參數(shù)都會被默默忽略仔引。如果傳遞多個值扔仓,你就必須要把它們封裝在單個值中傳遞,比如通過一個數(shù)組或者對象咖耘。

3.2 吞掉錯誤或異常

const p1 = new Promise(function (resolve,reject){
    throw new Error("error");
    resolve(1);
});
p1.then(function(value){
    console.log("a",value);
},function(err){
    console.log(err);
});
<!--輸出-->

<!--Error: error-->
<!--    at eval (lifting.js?f706:37)-->
<!--    at new Promise (<anonymous>)-->
<!--    at eval (lifting.js?f706:36)-->
<!--    at Object.<anonymous> (bundle.js:233)-->
<!--    at __webpack_require__ (bundle.js:20)-->
<!--    at Object.<anonymous> (bundle.js:83)-->
<!--    at __webpack_require__ (bundle.js:20)-->
<!--    at bundle.js:63-->
<!--    at bundle.js:66-->
<!--lifting.js?f706:54 a 2-->
<!--lifting.js?f706:51 Error: error-->
<!--    at eval (lifting.js?f706:37)-->
<!--    at new Promise (<anonymous>)-->
<!--    at eval (lifting.js?f706:36)-->
<!--    at Object.<anonymous> (bundle.js:233)-->
<!--    at __webpack_require__ (bundle.js:20)-->
<!--    at Object.<anonymous> (bundle.js:83)-->
<!--    at __webpack_require__ (bundle.js:20)-->
<!--    at bundle.js:63-->
<!--    at bundle.js:66-->

LazyMan 實現(xiàn)

1.代碼

function _LazyMan(name) {
    this.name = name;
    this.promises = [];
    var mfunc = () =>{
        console.log(`hello this is ${this.name}`);
        var p = Promise.resolve();
        return p 
    }
    this.promises.push(mfunc);
    var template = Promise.resolve();
    setTimeout(() => {
        this.promises.forEach(v =>{
            template = template.then(v);
        });
    }, 0)
}
_LazyMan.prototype = {
    sleep: function(time) {
        var pfunc = function() {
            var sp = new Promise(function(resolve, reject) {
                setTimeout(() => {
                    console.log(`暫停${time}s!`);
                    resolve();
                }, time * 1000);
            });
            return sp;
        }
        this.promises.push(pfunc);
        return this;
    },
    eat: function(food) {
        var epfunc = function() {
            console.log(`正在吃 ${food}`);
            var ep = Promise.resolve();
            return ep;
        }
        this.promises.push(epfunc);
        return this;
    }
}

function LazyMan(name) {
    return new _LazyMan(name);
}

LazyMan('yc').sleep(2).eat('shit').eat('peer').sleep(1).eat('shit').sleep('4').eat('banana');

如果不計較輸出形式翘簇,在構(gòu)造函數(shù)里面的for循環(huán)可以直接用 Promise.all()函數(shù)替代

2. 解析(大概意思可以看頂部手工圖)

2.1 箭頭函數(shù)

箭頭函數(shù)是ES6 新推出的形式,值得注意的是在setTimeOut的函數(shù)中用到了this儿倒,如果是傳統(tǒng)函數(shù)版保,這個this指向的是window,并不是_LazyMan夫否,但是如果是箭頭函數(shù)彻犁,this就是指向 _LazyMan

2.2 setTimeOut

setTimeOut函數(shù)并不會直接將回調(diào)函數(shù)放在事件循環(huán)隊列中,而是等到定時器時間到了之后才會將函數(shù)放到事件循環(huán)隊列中慷吊。正是基于setTimeOut函數(shù)的這種特性袖裕,所以在_LazyMan構(gòu)造函數(shù)中用setTimeout()去獲取promises中數(shù)組的數(shù)據(jù),此時promises的數(shù)據(jù)是調(diào)用鏈中的所有Promise對象溉瓶,如果不用setTimeout函數(shù)那么在構(gòu)造函數(shù)中急鳄,語句順序執(zhí)行,promises里的對象只有構(gòu)造函數(shù)中的一個Promise對象堰酿,鏈?zhǔn)秸{(diào)用函數(shù)中存入的Promise對象獲取不到疾宏。

2.3 鏈?zhǔn)秸{(diào)用

return this :返回整個對象,就能實現(xiàn)鏈?zhǔn)秸{(diào)用触创。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末坎藐,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子哼绑,更是在濱河造成了極大的恐慌岩馍,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,423評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抖韩,死亡現(xiàn)場離奇詭異蛀恩,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)茂浮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,147評論 2 385
  • 文/潘曉璐 我一進(jìn)店門双谆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來壳咕,“玉大人,你說我怎么就攤上這事顽馋∥嚼澹” “怎么了?”我有些...
    開封第一講書人閱讀 157,019評論 0 348
  • 文/不壞的土叔 我叫張陵寸谜,是天一觀的道長竟稳。 經(jīng)常有香客問我,道長程帕,這世上最難降的妖魔是什么住练? 我笑而不...
    開封第一講書人閱讀 56,443評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮愁拭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘亏吝。我一直安慰自己岭埠,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,535評論 6 385
  • 文/花漫 我一把揭開白布蔚鸥。 她就那樣靜靜地躺著惜论,像睡著了一般。 火紅的嫁衣襯著肌膚如雪止喷。 梳的紋絲不亂的頭發(fā)上馆类,一...
    開封第一講書人閱讀 49,798評論 1 290
  • 那天,我揣著相機(jī)與錄音弹谁,去河邊找鬼乾巧。 笑死,一個胖子當(dāng)著我的面吹牛预愤,可吹牛的內(nèi)容都是我干的沟于。 我是一名探鬼主播,決...
    沈念sama閱讀 38,941評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼植康,長吁一口氣:“原來是場噩夢啊……” “哼旷太!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起销睁,我...
    開封第一講書人閱讀 37,704評論 0 266
  • 序言:老撾萬榮一對情侶失蹤供璧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后冻记,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體睡毒,經(jīng)...
    沈念sama閱讀 44,152評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,494評論 2 327
  • 正文 我和宋清朗相戀三年檩赢,在試婚紗的時候發(fā)現(xiàn)自己被綠了吕嘀。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片违寞。...
    茶點(diǎn)故事閱讀 38,629評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖偶房,靈堂內(nèi)的尸體忽然破棺而出趁曼,到底是詐尸還是另有隱情,我是刑警寧澤棕洋,帶...
    沈念sama閱讀 34,295評論 4 329
  • 正文 年R本政府宣布挡闰,位于F島的核電站,受9級特大地震影響掰盘,放射性物質(zhì)發(fā)生泄漏摄悯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,901評論 3 313
  • 文/蒙蒙 一愧捕、第九天 我趴在偏房一處隱蔽的房頂上張望奢驯。 院中可真熱鬧,春花似錦次绘、人聲如沸瘪阁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽管跺。三九已至,卻和暖如春禾进,著一層夾襖步出監(jiān)牢的瞬間豁跑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,978評論 1 266
  • 我被黑心中介騙來泰國打工泻云, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留艇拍,地道東北人。 一個月前我還...
    沈念sama閱讀 46,333評論 2 360
  • 正文 我出身青樓壶愤,卻偏偏與公主長得像淑倾,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子征椒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,499評論 2 348