一道關於Promise應用的面試題

題目:紅燈三秒亮一次,綠燈一秒亮一次,黃燈2秒亮一次;如何讓三個燈不斷交替重複亮燈?(用Promse實現)html

三個亮燈函數已經存在:異步

function red(){
    console.log('red');
}
function green(){
    console.log('green');
}
function yellow(){
    console.log('yellow');
}

這道題首先考察Promise的應用,Promise的詳細說明請看個人這篇文章:閒話Promise機制。首先咱們須要一個函數來實現時間控制:函數

var tic = function(timmer, cb){
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            cb();
            resolve();
        }, timmer);
    });
};

若是把問題簡化一下,若是隻須要一個週期,那麼利用Promise應該這樣寫:code

var d = new Promise(function(resolve, reject){resolve();});
var step = function(def) {
    def.then(function(){
        return tic(3000, red);
    }).then(function(){
        return tic(2000, green);
    }).then(function(){
        return tic(1000, yellow);
    });
}

如今一個週期已經有了,剩下的問題是如何讓他無限循環。說道循環很容易想到for while do-while這三個,好比:htm

var d = new Promise(function(resolve, reject){resolve();});
var step = function(def) {
    while(true) {
        def.then(function(){
            return tic(3000, red);
        }).then(function(){
            return tic(2000, green);
        }).then(function(){
            return tic(1000, yellow);
        });
    }
}

若是你是這樣想的,那麼恭喜你成功踩了坑!這道題的第二個考查點就是setTimeout相關的異步隊列會掛起知道主進程空閒。若是使用while無限循環,主進程永遠不會空閒,setTimeout的函數永遠不會執行!blog

正確的解決方法就是這道題的第三個考查點——遞歸!!!解決方案以下:遞歸

var d = new Promise(function(resolve, reject){resolve();});
var step = function(def) {
    def.then(function(){
        return tic(3000, red);
    }).then(function(){
        return tic(2000, green);
    }).then(function(){
        return tic(1000, yellow);
    }).then(function(){
        step(def);
    });
}

總體代碼以下:隊列

function red(){
    console.log('red');
}
function green(){
    console.log('green');
}
function yellow(){
    console.log('yellow');
}

var tic = function(timmer, cb){
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            cb();
            resolve();
        }, timmer);
    });
};

var d = new Promise(function(resolve, reject){resolve();});
var step = function(def) {
    def.then(function(){
        return tic(3000, red);
    }).then(function(){
        return tic(2000, green);
    }).then(function(){
        return tic(1000, yellow);
    }).then(function(){
        step(def);
    });
}

step(d);

同時能夠看到雖然Promise能夠用來解決回調地獄問題,可是仍然不可避免的會有回調出現,更好的解決方案是利用Generator來減小回調:進程

var tic = function(timmer, str){
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            console.log(str);
            resolve(1);
        }, timmer);
    });
};


function *gen(){
    yield tic(3000, 'red');
    yield tic(1000, 'green');
    yield tic(2000, 'yellow');
}

var iterator = gen();
var step = function(gen, iterator){
    var s = iterator.next();
    if (s.done) {
        step(gen, gen());
    } else {
        s.value.then(function() {
            step(gen, iterator);
        });
    }
}

step(gen, iterator);
相關文章
相關標籤/搜索