一道關於Promise應用的面試題


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

三個亮燈函數已經存在:

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應該這樣寫:

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這三個,比如:

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的函數永遠不會執行!

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

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);


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM