• 一道关于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);
    
  • 相关阅读:
    【算法】数据结构与算法基础总览(上)数据结构篇
    Hangfire只允许同时运行同一个任务
    Redis缓存系列--(六)缓存和数据库一致性更新原则
    Redis缓存系列--(五)自定义Redis缓存注解的使用
    Redis缓存系列--(四)Redis基础数据类型在Java中的使用
    Redis缓存系列--(三)redis内存管理
    Redis缓存系列--(二)Redis持久化机制
    Redis缓存系列--(一)Redis的编译安装以及服务的开启
    深入理解Java虚拟机--垃圾收集器与内存分配策略
    分布式系统系列--(四)LVS基础知识点介绍
  • 原文地址:https://www.cnblogs.com/dojo-lzz/p/5495671.html
Copyright © 2020-2023  润新知