本文共 3183 字,大约阅读时间需要 10 分钟。
转载:http://web.jobbole.com/86150/
题目:红灯三秒亮一次,绿灯一秒亮一次,黄灯2秒亮一次;如何让三个灯不断交替重复亮灯?(用Promse实现)三个亮灯函数已经存在:
1 2 3 4 5 6 7 8 9 | function red ( ) { console . log ( 'red' ) ; } function green ( ) { console . log ( 'green' ) ; } function yellow ( ) { console . log ( 'yellow' ) ; } |
这道题首先考察Promise的应用,Promise的详细说明请看我的这篇文章:。首先我们需要一个函数来实现时间控制:
1 2 3 4 5 6 7 8 | var tic = function ( timmer , cb ) { return new Promise ( function ( resolve , reject ) { setTimeout ( function ( ) { cb ( ) ; resolve ( ) ; } , timmer ) ; } ) ; } ; |
如果把问题简化一下,如果只需要一个周期,那么利用Promise应该这样写:
1 2 3 4 5 6 7 8 9 10 | 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
这三个,比如:
1 2 3 4 5 6 7 8 9 10 11 12 | 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的函数永远不会执行!
正确的解决方法就是这道题的第三个考查点——递归!!!解决方案如下:
1 2 3 4 5 6 7 8 9 10 11 12 | 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 ) ; } ) ; } |
整体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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
来减少回调:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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 ) ; |