一道关于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);
时间: 2024-12-27 08:55:51

一道关于Promise应用的面试题的相关文章

一道关于随机算法的面试题(转)

今天碰到了一道面试题:原题大致是,每首歌曲都是一个评分,现在有2000首歌曲,要求实现一个随机播放器,每首歌曲播放的概率应该正比于它的评分,例如评分9.1的歌曲,和评分7.9的歌曲,播放的次数应该是91:79. 面试官给的答案是大致如此: 先把评分从小到大排序,之后把根据每首歌的评分,生成一个半闭开区间,然后生成一个随机数,看随机数落在哪个区间,就是选择的那首歌.例如,有三首歌,评分是[1,2,3] 那么应该是生成三个区间 [0-1,1-3,3-6],之后生成一个0-6之间的随机数,随机数落在哪

一道优雅面试题分析js中fn()和return fn()的区别_javascript技巧

在js中,经常会遇到在函数里调用其它函数的情况,这时候会有 fn() 这种调用方式,还有一种是 return fn() 这种调用方式,一些初学者经常会被这两种方式给绕晕了.这里用一个优雅的面试题来分析一下两种方式的不同之处.  var i = 0; function fn(){ i++; if(i < 10){ fn(); }else{ return i; } } var result = fn(); console.log(result); 这是一道隐藏了坑的面试题,看似很简单,大部分人可能想

从易于扩展扩展的角度来设计FizzBuzzWhizz

序言 最近FizzBuzzWhizz比较热,很多OSCER们也写出了自己的版本,有写的最快的,有写的最短的. 前面写过一篇文章叫 悠然乱弹:拉钩网FizzBuzzWhizz试题之悠然版解答,是悠然闲来无事写的一种算法,当时的文章只有写了实现与结果,但是没有详细说明作者为什么这么设计,所以导致一些人可能没有看明白,觉得有些设计是脱裤子放屁,多此一举. 今天悠然就来谈谈,悠然为什么这么设计,这么设计有什么好处?以与广大朋友们分享. 从题目来看,并不复杂,就是几种报数规则,并且有一些解决冲突时的规则,

windows server 2003共享之文件共享(二)

上次我们说到windows 2003文件共享在磁盘配额中的使用,那么现在我们再说说windows 2003共享文件在游湖漫游配置中的应用和相关的设置. 为了更能生动的说明问题,我还是和上一篇帖子一样,利用一道题目达到这种目的. 试题:你是公司的网络管理员,公司的办公网络是Windows 2003域环境.你想使员工无论使用哪台计算机都能获得他在前一次登录使用的桌面环境,该员工都可以修改并保存桌面环境.请问你应该如何实现这种功能. 分析:要达到这种功能,那么你必须要使用漫游配置文件,同时还要为每一个

关于DLL搜索路径顺序的一个问题

DLL的动态链接有两种方法.一种是加载时动态链接(Load_time dynamic linking).Windows搜索要装入的DLL时,按以下顺序:应用程序所在目录→当前目录→Windows SYSTEM目录→Windows目录→PATH环境变量指定的路径.      前天看到这几句,突然设计出一道自认绝妙的笔试题:"如果采用加载时动态链接的方式,Windows搜索要装入的DLL采用怎样的顺序?"这个是基础题,估计你很容易答出(答案就是上面的).呵呵,我还有后着呢:"你是

c++-一道C++面试题,不知道怎么考虑

问题描述 一道C++面试题,不知道怎么考虑 昨天去面试,有道题目不知道怎么考虑,哪位帮忙看下,指点一二? 一个超市有5个收银台,营业时间早8点晚8点,闲余时间是12:30-13:30,此时客人不用排队可以直接结账:繁忙时间16:30-19:00,此时每个收银台都是排满人的,假设买个队伍最多10人:求计算当天某个客人出现在2号收银台队伍里的第3个位置上的概率,写出过程和结果. 解决方案 12:30-13:30 结账 队伍0人 这时不可能出现在队伍第3人 概率为0 16:30-19:00 结账队伍1

Android多线程研究(4)从一道面试题说起

有一道这样的面试题:开启一个子线程和主线程同时运行,子线程输出10次后接着主线程输出100次,如此反复50次.先看下面代码: package com.maso.test; /** * * @author Administrator * 两个线程,其中是一个主线程,第一个线程先运行输出10次,主线程接着运行输出100次,如此反复50次 */ public class ThreadTest3 implements Runnable{ private static Test test; @Overri

经典算法(11) 一道有趣的GOOGLE面试题 --【解法2】

上一篇<白话经典算法系列之十一道有趣的GOOGLE面试题>中对一道有趣的GOOGLE面试题进行了详细的讲 解,使用了类似于基数排序的做法在O(N)的时间复杂度和O(1)的空间复杂度完成了题目的要求,文章发表后 ,网友fengchaokobe在评论中给出了另一种解法,见下图. 文字版: int Repeat(int *a, int n) { for(int i = 0; i < n; i++) { if(a[i] > 0) //判断条件 { if(a[ a[i] ] < 0)

经典算法(10) 一道有趣的GOOGLE面试题

最近在微博上看到一道有趣的GOOGLE面试题,见下图: 文字版: 一个 大小为n的数组,里面的数都属于范围[0, n-1],有不确定的重复元素,找到至少一个重复元素,要求O(1)空 间和O(n)时间. 这个题目要求用O(n)的时间复杂度,这意味着只能遍历数组一次.同时还要寻找重复 元素,很容易想到建立哈希表来完成,遍历数组时将每个元素映射到哈希表中,如果哈希表中已经存在这个 元素则说明这就是个重复元素.因此直接使用C++ STL中的hash_set(参见<STL系列之六 set与hash_set