一道 promise 亮灯问题的 思路演进 与 深坑 (JS异步机制) 分析

更新:增加使用 async/await 以及箭头函数的重构代码

问题

红灯三秒亮一次,绿灯一秒亮一次,黄灯2秒亮一次;如何让三个灯按照这个规律不断交替重复亮灯?(用Promse实现)三个亮灯函数已经存在:

function green() {
  console.log("green");
}

function yellow() {
  console.log("yellow");
}

function red() {
  console.log("red");
}

#思路解析

一道经典的考察 promise 应用的面试题

我们要解决两个问题,思路如下

###1 控制每盏灯,使其按某节奏闪烁

  • 命名为 flash 函数,参数为亮灯函数与时间参数
  • 应该会用到计时器

###2 控制三种灯闪烁的顺序

  • 命名为 control 函数。
  • 应该会用到promise,链式调用。

###3 实现重复不断的循环

  • 递归
  • 为什么不能使用 while 等实现无限循环

#代码演进

实现一次周期内的闪烁

通过上面 1、2 两点,可以得到如下代码

function flash(cb, time) {}

function control() {
   Promise.resolve()
    .then()
    .then()
    .then()
}

对于 control 函数

promise.then() 方法:

  • 期望的参数为函数
  • 返回的结果是一个promise

故而,then 方法的参数函数为

 function() {
     return flash(red, 3000);
 }

control 函数整体为

function control(promise) {
  promise
    .then(function() {
      return flash(red, 3000);
    })
    .then(function() {
      return flash(green, 1000);
    })
    .then(function() {
      return flash(yellow, 2000);
    });
}

flash 函数

由上可知,它应该返回一个完成态的 promise。

由于要结合定时器使用,采用promise构造函数的写法,代码如下

function flash(cb, time) {
  return new Promise(function executor(resolve, reject) {
    setTimeout(() => {
      cb(), resolve();
    }, time);
  });
}

目前,已经实现了一个周期内的亮灯控制。

实现重复闪烁

要实现不断重复,考虑递归

为什么 while 不行

当然,说到无限循环,很容易想到 while 循环等方法。事实上,这种办法行不通。这涉及到 JavaScript 异步运行机制,参考 单线程 JavaScript 的异步机制与经典 for 循环面试题

简单地说

  • 一次 事件循环 中,同步代码先入 执行栈 执行,异步代码分情况将其任务注册到 任务队列 中。

  • 只有执行栈清空,主线程 才会从任务队列中读取任务,使其入栈执行

  • 类似 while(true) 这样的代码,会永久占据主线程,使得执行栈永远不清空。

  • 所以,任务队列中等待的亮灯任务也就永无出头之日。

递归

灯光闪烁一个周期,即 control 函数运行一次之后,让 control 函数递归调用自身即可。

还是用 then 方法控制流程,加一个 .then() ,其参数按规定是一个函数,在该匿名函数内部调用函数本身,实现递归。

control 函数最终如下

function control() {
  Promise.resolve()
    .then(function() {
      return flash(red, 3000);
    })
    .then(function() {
      return flash(green, 1000);
    })
    .then(function() {
      return flash(yellow, 2000);
    })
    .then(function() {
      control();
    });
}

#完整代码


function green() {
  console.log("green");
}

function yellow() {
  console.log("yellow");
}

function red() {
  console.log("red");
}

function flash(cb, time) {
  return new Promise(function executor(resolve, reject) {
    setTimeout(() => {
      cb(), resolve();
    }, time);
  });
}

function control() {
  Promise.resolve()
    .then(function() {
      return flash(red, 3000);
    })
    .then(function() {
      return flash(green, 1000);
    })
    .then(function() {
      return flash(yellow, 2000);
    })
    .then(function() {
      control();
    });
}

control();

重构

const red = () => console.log('red')
const green = () => console.log('green')
const yellow = () => console.log('yellow')

const controlLight = color => time => (
  new Promise((resolve, reject) => {
    setTimeout(() => {
      color()
      resolve()
    }, time)
  })
)

const controlOrder = async () => {
  await controlLight(red)(3000)
  await controlLight(green)(1000)
  await controlLight(yellow)(2000)
  await controlOrder()
}

controlOrder()
发布了49 篇原创文章 · 获赞 40 · 访问量 11万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章