「2021年跳槽必看」一次字节面试经历

·  阅读 229
「2021年跳槽必看」一次字节面试经历

零 · 引言

此次面试记录分享,对于react面试者更为实用,因为本人常用的技术栈为react,感觉面试官很nice,面试也是面试你擅长的部分,所以你要在简历里突出你的擅长。准备好小本本开始面试之旅吧!

在进行简单的自我介绍后,开始讨论react的问题,涉及比较多,本次主要记录了一下几个问题

壹 · setState 异步同步机制

以下的setState是分几批次执行?

saveState =() =>{
    this.setState({ num: 1 })
    this.setState({ num2: 1 })
    this.setState({ num3: 1 }, () => {
      this.setState({ num: 3 })
      console.log('callback', this.state)
    })
    this.setState({ num4: 1 })
    console.log('num4', this.state)
}
复制代码

想象不如实操

  • 在回调函数打印输出结果中没有对num的更新
  • componentDidUpdate 生命周期中

如果存在多个回调函数呢?

import React, { Component } from 'react'
import './App.css';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }
  saveState = () => {
    this.setState({ num: 1 })
    this.setState({ num2: 1 })
    this.setState({ num3: 1 }, () => {
      this.setState({ num: 3 })
      console.log('callback', this.state)
    })
    this.setState({ num6: 1 }, () => {
      this.setState({ num: 7 })
      console.log('callback6', this.state)
    })
    this.setState({ num4: 1 })
    console.log('num4', this.state)
  }
  componentDidUpdate = (prevProps, prevState, snapshot) => {
    console.count('componentDidUpdate')
    console.log("🚀 ~ componentDidUpdatePrev", prevProps, prevState, snapshot)
    console.log("🚀 ~ componentDidUpdate", this.state)
  }
  render() {
    console.count('render')
    return (
      <div onClick={this.saveState}>测试</div>
    );
  }
}

export default App;
复制代码
  • 点击测试,多个回调函数仅触发一次回调
  • 直接从1变成了7

贰 · fieber 算法解决的问题

React Fiber的目标是提高其对动画,布局和手势等区域的适用性。它的标题功能是增量渲染:将渲染工作分成多个块并将其分布到多个帧中的能力。

其他关键功能包括随着新更新的出现而暂停,中止或重用工作的功能;为不同类型的更新分配优先级的能力;和新的并发原语。 React->Fieber

叁 · 实现 promise.then()

完整的promise实现

  • 状态和值的变化处理
  • 指定默认返回函数
  • 使用setTimeout实现异步执行
(function () {
    function MyPromise(executor) {
        //参数校验
        if (typeof executor !== 'function') {
            throw new TypeError("MyPromise resolve" + executor + "is not a function")
        }
        //设置默认值
        var _this = this
        this.PromiseStatus = 'pending'
        this.PromiseValue = undefined
        this.resolveFunc = function () { }//匿名空函数,未使用传递then,Function.prototype
        this.rejectFunc = function () { }
        //修改实例状态value方法,只有当前状态为pending才能修改状态
        function change(status, value) {
            if (_this.PromiseStatus !== 'pending') return;
            _this.PromiseStatus = status
            _this.PromiseValue = value
            //通知基于then注入的某个方法执行(异步的)
            var delayTimer = setTimeout(function () {
                clearTimeout(delayTimer)
                delayTimer = null
                //
                var status = _this.PromiseStatus,
                    value = _this.PromiseValue;
                status === 'fulfilled' ?
                    _this.resolveFunc.call(_this, value) :
                    _this.rejectFunc.call(_this, value)
            }, 0)
        }
        //处理设定传递给executor,并且执行可以需要修改实例状态和value值resolve/reject函数
        //new 立即执行传入函数executor
        //executor函数执行出现错误,也会把实例的状态改为失败,且value的失败原因
        try {
            executor(function resolve(value) {
                change('fulfilled', value)
            }, function reject(reason) {
                change('rejected', reason)
            })
        } catch (err) {
            change('rejected', err.message)
        }
    }
    MyPromise.prototype.then = function (resolveFunc, rejectFunc) {
        //参数不传默认值的处理:目的是为了实现状态顺延
        if (typeof resolveFunc !== 'function') {
            //给不穿的时候默认返回一个函数
            resolveFunc = function (value) {
                return MyPromise.resolve(value)
            }
        }
        if (typeof rejectFunc !== 'function') {
            rejectFunc = function (value) {
                return MyPromise.reject(value)
            }
        }
        var _this = this
        // this.resolveFunc = resolveFunc
        // this.rejectFunc = rejectFunc
        //每次执行.then都会返回一个新的promise实例
        return new MyPromise(function (resolve, reject) {
            //返回的新实例的成功和失败(执行resolve/ reject):
            //由于函数是否报错决定(或返回值是否为新的Promise实例来决定)
            _this.resolveFunc = function (value) {
                try {
                    var x = resolveFunc.call(_this, value)
                    //执行结果如果是Promise实例,x.then判断执行成功或失败,否则返回值
                    x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
                } catch (err) {
                    reject(err.message)
                }
            }
            _this.rejectFunc = function (reason) {
                try {
                    var x = rejectFunc.call(_this, reason)
                    x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
                } catch (err) {
                    reject(err.message)
                }

            }
        })
    }
    MyPromise.prototype.catch = function (rejectFunc) {
        return this.then(null, rejectFunc)
    }
    MyPromise.resolve = function (value) {
        return new MyPromise(function (resolve) {
            resolve(value)
        })
    }
    MyPromise.reject = function (reason) {
        return new MyPromise(function (_, reject) {
            reject(reason)
        })
    }
    MyPromise.all = function (promiseArr) {
        return new MyPromise(function (resolve, reject) {
            var index = 0,
                values = []
            for (var i = 0; i < promiseArr.length; i++) {
                //利用闭包的方式保存循环的每一项的索引
                (function (i) {
                    var item = promiseArr[i];
                    //如果当前项不是promise:直接算当前项成功
                    !(item instanceof MyPromise) ?
                        item = new MyPromise(item) :
                        null
                    //如果是当前项是promise
                    item.then(function (value) {
                        index++;
                        values[i] = value
                        if (index >= promiseArr.length) {
                            resolve(values)
                        }
                    }).catch(function (reason) {
                        //只有有一个失败,整体失败
                        reject(reason)
                    })
                    return;
                })(i)
            }
        })
    }
    window.MyPromise = MyPromise
})()

复制代码

肆 · 实现 splice

方案一:使用新数组,简单实现

  • 获取原数组
  • 判断临界值
  • 返回新数组
  • 给原始的Array添加属性
const arr = [1, 2, 3]
/**
 * 
 * @param {*} 路径 
 * @param {*} removeLength 删除个数
 * @param {*} arguments 替换元素
 */
function spliceTest(index, removeLength, ...arguments) {
    let res = []
    let array = Object(this);//获取原数组
    let otherParams = arguments
    const endIndex = index + removeLength
    for (let i = 0; i < array.length; i++) {
        if (i == index) {//插入数组位置
            res.push(...otherParams)
        } else if (i > index && i < endIndex) {//删除
            continue
        } else {
            res.push(arr[i])//添加
        }
    }
    return res
}
Array.prototype.spliceTest = spliceTest //给原始的Array添加属性
console.log("输出:", arr.spliceTest(1, 1, 4, 5))
复制代码

方案二:基于原数组实现

在对比后感觉这个文章比较详细,大家可以参考看下 如何手动实现数组的splice方法 ? (V8源码级别)

收获

感觉通过面试,不仅是为了找工作,也可以给你的未来的技术学习指路,面试官可遇而不可求,一个好的面试过程,可以给你带来好奇的想象,明确或是加深对未来技术追求的目标。

思维是开发的源泉:优化思维、反向思维、对比思维、打破思维

分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改