面试记录
2024.06.19晚上八点,参与了远方
大佬模拟面试,记录一下过程中的一些问题。
这里给大佬 引个流 ,特别感谢远方
花费自己的时间给本人面试,给群友输出知识。
面试准备
- 需要对要面试的公司有一定的了解,防止冷场
- 需要对简历中写的东西负责,所有的细节一定要闭环
- 临场遇到准备以外的问题别怕,想好了闭环再有条不紊的回答,最差也就是没用过
面试吭哧瘪肚的问题
有几个突出的问题记录一下,查漏补缺!!!
ref解构
从所周知,vue3中基本上都是面向ref
开发,通过ref
定义的响应式变量在使用的时候需要带上.value
,但是某些情况下他会自动解构其中的.value
模板语法1
当ref
是顶级变量的时候,这个时候可以直截了当。
<template>
<!-- 0 -->
<div>{{ count }}</div>
<!-- 1 -->
<div>{{ count + 1 }}</div>
</template>
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
模板语法2
当ref
是内部变量的时候,这个时候可以不了一点。
<template>
<!-- 0 -->
<div>{{obj.val}}</div>
<!-- [object Object]1 -->
<div>{{ obj.val + 1 }}</div>
</template>
<script setup>
import { ref } from 'vue'
const obj = {
val: ref(0)
}
</script>
因为obj.val
实际上是一个ref对象,此时使用obj.val.value
就可以了。
同理,const { val } = obj
,这么玩也是会自动解构的,相当于模板语法1。
reactive
ref对象嵌套到另一个响应式对象的属性中时,访问属性会自动解包
<template>
<!-- 0 -->
<div>{{obj.val}}</div>
<!-- 1 -->
<div>{{ obj.val + 1 }}</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
const count = ref(0)
const obj = reactive({
val: count
})
</script>
当然了,这里的reactive
换成ref
那就相当于直接定义了一个ref
,自然也是一样ok的
新的ref?
如下文myRef
写法会直接报错,而myRef2
是正确的
import { ref, Ref, UnwrapRef } from 'vue'
// 不能将类型“Ref<UnwrapRef<T>>”分配给类型“Ref<T>”。
// 不能将类型“UnwrapRef<T>”分配给类型“T”。
// const myRef = <T>(state: T): Ref<T> => {
// return ref(state)
// }
const ref2Ref = <T>(state: T): Ref<UnwrapRef<T>> => {
return ref(state)
}
const total = ref2Ref(count)
源码:
export function ref<T>(value: T): Ref<UnwrapRef<T>>
export function ref<T = any>(): Ref<T | undefined>
export function ref(value?: unknown) {
return createRef(value, false)
}
问题在于,泛型 T
可能是任何类型,包括但不限于基本类型、对象、数组,以及响应式引用。当你的函数声明返回 Ref<T>
时,你实际上是在承诺无论 T
是什么类型,返回的都将是 Ref<T>
类型。但是,如果 T 是一个响应式引用,ref(state)
将返回 Ref<UnwrapRef<T>>
,这与 Ref<T>
不兼容
bff
Backend For Frontend(服务于前端的后端)。
鲁迅曾经说过:如果一个问题解决不掉,那么就加一个中间层,还解决不掉?再加一个中间层。
问题
有问题才有解决方案,他解决了什么呢?因为前端浏览器的上限是6个,而同一时间可能请求个数有茫茫多,暂定20个。
那么前面接口堵塞的时候,后面的接口就只能强行排队了。
这个时候就可以用node
去实现一个bff
,因为node
请求后台服务绕过了浏览器这一层,没有并发限制,等到所有请求完成以后统一返回给web
,就从另外一个层面解决了大量请求慢导致首页加载速度的问题。
Web Worker
既然提到了bff
,自然就把Web Worker
给带出来了,他是独立于 Web 应用程序主执行线程的后台线程中运行的脚本。
从定义上可以看出来,他只是协助解决js脚本单线程的问题的,而不是解决上述浏览器接口数目限制问题的。
应用场景:
- 复杂计算:图像处理、音频处理、视频处理等复杂的数据处理
- 后台下载:当需要下载大量数据时,可以使用 Web Worker 在后台进行数据的下载和处理,以避免阻塞用户界面
- 数据处理:当需要对大量数据进行处理或者排序时,可以使用 Web Worker 将处理逻辑放在后台线程中进行,提高处理的效率
- 实时通信:使用 Web Worker 来处理实时通信的逻辑。在主线程可以与 Web Worker 进行通信,从而实现实时的数据交换
面试题
填充以下代码使得满足以下要求:
- 只修改类
Scheduler
即满足异步请求的并发数控制 addTask
返回的是一个promise
类型addTask
以后每次执行的方法数目不得超过max
个stack
中压栈的方法大于max
个的时候,应该自动执行到空为止
// 最多同时执行n个异步任务
class Scheduler {
constructor(max) {
this.max = max || 2
this.stack = []
}
addTask(asyncTask) {
return new Promise((resolve, reject) => {
})
}
}
const scheduler = new Scheduler()
scheduler.addTask(() => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(1)
}, 1000)
})
}).then(console.log)
scheduler.addTask(() => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(2)
}, 2000)
})
}).then(console.log)
scheduler.addTask(() => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(3)
}, 3000)
})
}).then(console.log)
result
// 最多同时执行n个异步任务
class Scheduler {
constructor(max) {
this.max = max || 2
this.stack = []
this.runCount = 0
this.map = new WeakMap()
}
run() {
if (this.stack.length > 0 && this.runCount < this.max) {
const asyncTask = this.stack.shift()
this.runCount++
const { resolve, reject } = this.map.get(asyncTask)
asyncTask().then(resolve).catch(reject).finally(() => {
this.runCount--
this.run()
})
}
}
addTask(asyncTask) {
return new Promise((resolve, reject) => {
this.map.set(asyncTask, { resolve, reject })
this.stack.push(asyncTask)
this.run()
})
}
}
const scheduler = new Scheduler()
scheduler.addTask(() => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(1)
}, 1000)
})
}).then(console.log)
scheduler.addTask(() => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(2)
}, 2000)
})
}).then(console.log)
scheduler.addTask(() => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(3)
}, 3000)
})
}).then(console.log)