关于javascript:一道别人分享的阿里面试题

前两天看到一个他人写的面试经验一次羞愧难当的阿里前端口试经验,本次换工作不会再寻求任何阿里工作机会,看了下题目本人试着写了下,短短续续差不多写了1天终于完后能力了。

实现一个红绿灯的需要

要求如下:

/** 1. 信号灯控制器
用 React 实现一个信号灯(交通灯)控制器,要求:

  1. 默认状况下,
    1.1. 红灯亮20秒,并且最初5秒闪动
    1.2. 绿灯亮20秒,并且最初5秒闪动
    1.3. 黄灯亮10秒
    1.4. 秩序为 红-绿-黄-红-绿-黄
  2. 灯的个数、色彩、持续时间、闪动工夫、灯光秩序都可配置,如:
    lights=[{color: ‘#fff’, duration: 10000, twinkleDuration: 5000}, … ]

*/

剖析

js业务逻辑局部

先遍历一轮即先亮一组灯(默认红绿黄),再循环遍历灯

  1. 先要实现一个期待函数

首先有一个期待函数,即sleep函数
罕用的sleep函数如下:

function sleep(time){
    return new Promise((resolve)=>{
        setTimeout(resolve,time)
    })
}

2.亮一颗灯逻辑
先亮N秒再闪M秒,其中M可能为0

async function Light(currentLight) {
    const current = currentLight
    console.log('current', current)
    const currentColor = current.color // 灯的色彩
    const currentTime = current.time // 常亮的工夫
    const flashTime = current.flashingTime // 闪动工夫
    console.log(Date.now(), '开始亮', currentColor, '色的灯')
    await sleep(currentTime)
    if (flashTime > 0) {
    console.log(Date.now(), '开始闪', currentColor, '色的灯')
    await sleep(flashTime)
    }
    console.log(Date.now(), '敞开', currentColor, '色的灯')
}

3.亮一组灯的逻辑

async function roundLight(lights) {
    for (let item of lights) {
        console.log('遍历灯:', item.color)
        await Light(item)
    }
    return true // 增加返回值,标记一轮已完结
}

4.组与组间有限循环
首先想到的是setInterval(fn,time),其中time为组内所有的亮灯加闪灯的工夫的和。

// 计算亮一轮灯须要的工夫和
function getARoundTime(Lights) {
    let round = Lights
    let totalTime = 0
    for (let item of round) {
    totalTime += item.time + item.flashingTime
    }
    console.log('所有色彩的灯都亮完一轮须要工夫为:', totalTime)
    return totalTime
}
// 首次写法是这样的
async function lightInterval(Lights) {
    // 获取亮一轮须要的工夫
    let totalTime = getARoundTime(Lights)
    // 先亮一轮
    await roundLight(Lights)
    // 每隔一轮从新执行下一轮
    setInterval(async (Lights) => {
        await roundLight(Lights)
    }, totalTime)
}

执行后发现逻辑有问题,亮一轮后会等一轮工夫后才再开始亮,后续失常亮
调整逻辑为先放个一轮的定时器,让第一轮开始时setInterval也开始执行
批改后变成了这样

async function lightInterval(Lights) {
    let totalTime = getARoundTime(Lights)
    setTimeout(() => {
        setInterval(async () => {
            await roundLight(Lights)
        }, totalTime)
    })
    await roundLight(Lights)
}

这样貌似能够,然而多看几轮会发现问题,会呈现上一轮尚未齐全完结就开始执行下一轮的状况
因为每一轮执行的工夫并不齐全准确等于要求的工夫,会有毫秒级的误差
累积多了误差就显著了,所以不能应用setInterval

5.另一种组与组间有限循环的办法

async function roundInterval(Lights) {
    // 所有色彩的灯先亮一轮
    const roundResult = await roundLight(Lights)
    // 完结后调用本身,继续执行
    if (roundResult) {
        await roundInterval(Lights)
    }
}

js逻辑实现之后该写页面了

页面局部

  1. 如何在打console的中央执行页面内容的刷新?

通过setState让状态发生变化,天然页面就会刷新

// 先在页面上展现灯的状态及色彩
function ShowLight(props) {
    return (
        <span>
            以后展现的是{props.color},以后状态是{props.status}
        </span>
    )
}

应用state存储灯的色彩和状态,先显示一轮逻辑

    class LightTwo extends React.Component {
        constructor(props) {
          super(props)
          this.state = {
            currentColor: '',//保留灯的色彩
            currentStatus: '',//保留灯的状态
          }
        }
        async componentDidMount() {
          console.log('componentDidMount')
          //  先亮一颗灯试一下(取数组里的第一颗灯)
          const currentLight = this.props.options[0]
          await this.LightState(currentLight)
        }
        async LightState(currentLight) {
          const currentColor = currentLight.color
          const currentTime = currentLight.time
          const flashTime = currentLight.flashingTime
          this.setState({ currentColor, currentStatus: 'on' })
          console.time('亮' + currentColor + '灯耗时')
          await sleep(currentTime)
          console.timeEnd('亮' + currentColor + '灯耗时')
          if (flashTime > 0) {
            this.setState({ currentColor, currentStatus: 'flash' })
            console.time('闪' + currentColor + '灯耗时')
            await sleep(flashTime)
            console.timeEnd('闪' + currentColor + '灯耗时')
          }
        }
        render() {
          return (
            <div>
              <ShowLight
                status={this.state.currentStatus}
                color={this.state.currentColor}
              />
            </div>
          )
        }
      }

而后显示多轮逻辑详见完整版

2.灯的闪动成果实现

通过调整透明度的动画有限循环来实现闪动成果

@keyframes myAnimation {
    0% {
        opacity: 0;
        filter: alpha(opacity=0);
    }
    100% {
        opacity: 1;
        filter: alpha(opacity=100);
    }
}
.flash {
    -webkit-animation: myAnimation 0.6s infinite;
    animation: myAnimation 0.6s infinite;
}

3.react管制款式的展现
通过增加和移除className的办法来实现管制款式

render() {
    // 其余类名间接写死
    // 多个类名用空格拼接
    // 拼接以后色彩的类 
    let classNames = 'demo-1 ' + this.state.currentColor
    if (this.state.currentStatus) {
    //   拼接以后状态的类
    classNames += ' ' + this.state.currentStatus
    }
    return (
    <div>
        <ShowLight
           // 把类名传递给组件
            classNames={classNames}
            status={this.state.currentStatus}
            color={this.state.currentColor}
        />
    </div>
    )
}
// 显示组件
function ShowLight(props) {
    return (
        <>
        <span>
            {' '}
            以后展现的是{props.color},以后状态是{props.status}
        </span>
        <!-- 不能再这里写class="foo"(该类间接被废除) 或者 className="foo"(若写在变量前面则变量不失效)  之类的写法 -->
        <span className={props.classNames}></span>
        </>
    )
}

进行红绿灯

// 办法一:清空函数
closeLight() {
    // 设置组间循环为空
    this.roundInterval = () => {}
    // 设置组内循环为空
    this.roundLight = () => {}
    // 设置管制单个灯的函数为空
    this.LightState = function () {}
    this.setState({
        currentColor: '',
        currentStatus: '',
    })
}
// 办法二:批改传入的灯数组为空数组 ---感觉这种办法更好

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理