如果我是面试官,我肯定会问你这些题目(持续更新)

548 阅读5分钟

以下答案仅供参考,大部分题目都是考察灵活应用某些概念,不是生记硬背的

1、nodejs

1.1、nodejs线程

QA:我们都知道nodejs是单线程的,但是如果仔细看过Nodejs启动的进程,你还是会发现其实是有7个线程的。那么请问这7个线程都是负责哪些工作的?

单线程只是因为执行js代码的只有一个,这个也叫作主线程。但是像GC这些事情是不会主线程上执行的,因此7个线程包括了:

  • 主线程:编译、执行代码。
  • 编译/优化线程:在主线程执行的时候,可以优化代码。
  • 分析器线程:记录分析代码运行时间,为 Crankshaft 优化代码执行提供依据。
  • 垃圾回收的几个线程。
  • libuv的event-loop线程,这个可以参考:nodejs深入学习系列之libuv基础篇(二)
  • 还有一个备用的线程池,libuv提供的,这个没用到的话不会计算到7个线程里面

1.2、v8

QA:了解过v8吗?v8里面也有一个叫做context的东西,每当我们需要切换上下文的时候都会切换这个context,比如一个worker到另外一个worker。但是切换上下文涉及到堆栈以及一些别的操作,可以说是比较费时的。那么v8里面是用了什么技术来优化这个上下文的切换?

该题目考查对v8的基本了解程度,如果有看过v8的基本官方文档介绍的话,都知道V8利用大量缓存来提高context切换的成本。

参考:[译文]V8学习的高级进阶

1.3、nodejs监控

QA:做过Nodejs的进程状态信息监控吗?除了一般监控的CPU、内存之外,可能还需要监控event loop的平均调度时间,那么请问有什么办法可以统计到event loop的延迟时间呢?

该题目考察对event loop的了解,如果知道event loop的原理,那么我们可以主动加入一个定时器,然后就可以计算加入定时器的时间和回调函数被调用的时间差与定时器设置的超时时间之差,二者便是event loop的延迟时间。

伪代码实现:

const now = Date.now() // 如果需要精度更加精确,可以使用process.hrtime.bigint()
setTimeout(() => {
  const cost = Date.now() - now
  const eventloopDelay = cost - 100 // 这个时间便是eventloop的延迟时间
}, 100)

1.4、任务队列

QA:说一下下面代码的打印结果:

const EventEmitter = require('events')
class EE extends EventEmitter {}
const yy = new EE()
console.log('测试开始')
yy.on('event', () => console.log('我是EventEmitter触发的事件回调'))
setTimeout(() => {
  console.log('0 毫秒后到期的定时器回调1')
  process.nextTick(() => console.log('我是0毫秒定时器1加塞的一个微任务'))
}, 0)
setTimeout(() => {
  console.log('0 毫秒后到期的定时器回调2')
  process.nextTick(() => console.log('我是0毫秒定时器2加塞的一个微任务'))
}, 0)
setImmediate(() => console.log('immediate 立即回调'))
process.nextTick(() => console.log('process.nextTick 的第一次回调'))
new Promise((resolve) => {
  console.log('我是promise')
}).then(() => {
  yy.emit('event')
  process.nextTick(() => console.log('process.nextTick 的第二次回调'))
  console.log('promise 第一次回调')
})
.then(() => console.log('promise 第二次回调'))
console.log('测试结束?')

该题的解析参考:js语言中那些让你抓狂又容易混淆的概念(建议收藏)

1.5、express的中间件

QA:说一下当请求:curl 127.0.0.1:3000/api/test1的时候下面代码的打印结果:

const express = require('express')

const app = express()

const sleep = (mseconds) => new Promise((resolve) => setTimeout(() => {
  console.log('sleep timeout...')
  resolve()
}, mseconds))

app.use(async (req, res, next) => {
  console.log('I am the first middleware')
  const startTime = Date.now()
  console.log(`================ start ${req.method} ${req.url}`, { query: req.query, body: req.body });
  next()
  const cost = Date.now() - startTime
  console.log(`================ end ${req.method} ${req.url} ${res.statusCode} - ${cost} ms`)
})
app.use((req, res, next) => {
  console.log('I am the second middleware')
  next()
  console.log('second middleware end calling')
})

app.get('/api/test1', async(req, res, next) => {
  console.log('I am the router middleware => /api/test1')
  await sleep(2000)
  res.status(200).send('hello')
})

app.listen(3000)
console.log('server listening at port 3000')

该题的解析参考:js语言中那些让你抓狂又容易混淆的概念(建议收藏)

2、javascript

2.1、修饰器的用法

QA:请将下面代码使用修饰器的功能,将所有公共部分抽象出一个修饰函数,以便可以简单使用在各个请求之中

class allApisClass {
  async fetchGoods(params) {
    Toast.loading('请稍候...')
    try {
      const info = await fetchHandle(fetchGoods, params)
      Toast.close()
      return info
    } catch (err) {
      Toast.close()
      Toast.error(err.msg)
    }
  }
}

比如抽象后的修饰器是:decorator,那么我可以这么简单地使用:

class allApisClass {
  @decortor()
  async fetchGoods(params){
    const info = await fetchHandle(fetchGoods, params)
    return info
  }
}

请实现对应的修饰器函数:

function decorator(target, propertyKey, descriptor) {

}

该题目的解析参考:你以为装饰器那么容易学吗?

2.2、关于页面访问时间的问题

QA:你觉得使用react框架的时候,用componentWillUnMount来统计访问时间靠谱吗?为什么?如果是你做,你会怎么实现?

统计页面访问时间是从页面渲染完成开始计时到页面关闭,如果使用componentWillUnMount来统计页面关闭的时间是统计不到的,因为当页面关闭时并不会触发这个事件,该事件能够被触发存在的前提是页面仍然在浏览器中显示,所以是不靠谱的。监听页面关闭的只能使用原生的unload事件。

2.3、奇思妙想

QA:如何快速统计字符串某个字符出现的次数?如何使用正则表达式快速计算出现次数最多的字符?

第一个问题的答案是利用split

str.split('a').length - 1

第二个问题的答案是利用正则表达式的捕捉组概念:/(\w)\1+/g

const str = 'fhsdfhdsofsifjisffs'
const arr = str.split(''); //把字符串转换为数组
//首先进行排序,这样结果会把相同的字符放在一起,然后再转换为字符串
const str = arr.sort().join('')
const value = ''
const index = 0
//匹配字符,且重复这个字符,重复次数至少一次
const re = /(\w)\1+/g
str.replace(re, function ($0, $1) {
  console.log($0, $1)
  //如果index保存的值小于$0的长度就进行下面的操作
  if (index < $0.length) {
    index = $0.length;
    value = $1;
 }
})