今天去面试,面试官让我写一个红绿灯,让我快乐了好久!!!

212 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第N天,点击查看活动详情 >>PS:第3天。

image.png

请通过Promise,async.await 三者实现简单的信号灯

转换流程:30s、灯3s、灯2s,往复循环在控制台打印即可,不需要实现界面。

不需要我实现界面??? 不!! 我偏要实现!!!

image.png image.png

01 来来来!!上代码

html

    <ul>
      <li class="red"></li>
      <li class="green"></li>
      <li class="yellow"></li>
      <span></span>
    </ul>

CSS

  <style>
    ul {
      list-style: none;
      width: 400px;
      height: 100px;
      background-color: #ccc;
      display: flex;
      margin: 0;
      padding: 0;
    }
    ul li {
      width: 80px;
      height: 80px;
      border-radius: 50%;
      margin: 10px;
      opacity: 0.2;
    }
    ul li:nth-child(1) {
      background-color: red;
    }
    ul li:nth-child(2) {
      background-color: green;
    }
    ul li:nth-child(3) {
      background-color: yellow;
    }
    span {
      display: inline-block;
      width: 100px;
      height: 100px;
      background-color: #666;
      text-align: center;
      line-height: 100px;
      color: red;
      font-size: 60px;
    }
    .active {
      opacity: 1;
    }
  </style>

JS

  <script>
      let lis = document.querySelectorAll("li");
      let span = document.querySelector("span");
      function timer(color, delay) {
        let d = delay;
        document.querySelector("span").innerHTML = d / 1000;
        return new Promise((resolve, reject) => {
          let timeId = setInterval(() => {
            if (d <= 1000) {
              return clearInterval(timeId);
            } else {
              d -= 1000;
              console.log(color, d);
              document.querySelector("span").innerHTML = d / 1000;
            }
          }, 1000);
          document.querySelector("." + color).classList.add("active");
          let timeId2 = setTimeout(() => {
            lis.forEach((item) => {
              item.classList.remove("active");
            });
            resolve();
          }, delay);
        });
      }
      async function light() {
        await timer("red", 10000);
        await timer("green", 5000);
        await timer("yellow", 3000);
        light();
      }
      light();
    </script>

02 代码剖析

    ul li {
      width: 80px;
      height: 80px;
      border-radius: 50%;
      margin: 10px;
      opacity: 0.2;
    }
   .active {
      opacity: 1;
    }
  • 红绿灯三个灯的亮暗状态由active控制(因此初始三个灯的透明度opacity调为0.2)
  • Active的样式为opacity:1 ,因此控制灯的亮暗,span标签显示当前秒数
     let lis = document.querySelectorAll("li");
     let span = document.querySelector("span");
     function timer(color, delay) {
       let d = delay;
       document.querySelector("span").innerHTML = d / 1000;
       return new Promise((resolve, reject) => {
         let timeId = setInterval(() => {
           if (d <= 1000) {
             return clearInterval(timeId);
           } else {
             d -= 1000;
             console.log(color, d);
             document.querySelector("span").innerHTML = d / 1000;
           }
         }, 1000);
         document.querySelector("." + color).classList.add("active");
         let timeId2 = setTimeout(() => {
           lis.forEach((item) => {
             item.classList.remove("active");
           });
           resolve();
         }, delay);
       });
     }

获取DOM

  1. 获取dom,lis伪数组(所有的li标签),span标签
  2. 创建函数命名为timer,传参:颜色 每个灯总的持续时间
  3. 声明变量d接收灯持续时间的参数,把span标签的内容改为灯的总持续时间

间歇定时器

  1. return 回一个promise函数,并创建打开间歇定时器setInterval
  2. 在间歇定时器中判定灯亮的总时长是否已小于等于1秒,如果是,则关掉定时器
  3. 如果不小于1秒,那灯亮的总时长每次定时器运行就减一秒(-= 1000 ),并设置span标签内的内容,灯亮的总时长除以1000 (要显示的秒数)
  4. 获取当前灯亮颜色的标签,并为其添加 active 样式

延时定时器

  1. 在延时定时器中遍历lis伪数组,删除他们的 active 样式 ( 此延时定时器的总时长是灯亮的总时长,因此可以达到当每个灯亮的总时长结束后就删除所有 active )
  2. 在延时定时器中调用promise的 resolve(),返回成功的结果

async/await阻塞运行

  1. 使用async/await调用三次第一次创建的函数,传参 依次为 三个灯的颜色,和总的持续时间
  2. 使用递归调用自己,,,最后调用第二次创建的函数

完结!!!撒花!!🌸🌸🌸🌸🌸🌸🌸🌸🌸🌸🌸🌸

image.png

image.png