題目:紅燈三秒亮一次,綠燈一秒亮一次,黃燈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);