nodejs面试

1.node js是什么?

node js 是基于chome v8引擎的javascript运行时(运行环境)

2.1nodejs和前端js的区别
  • 语法层面
    1.前端js使用js web api
    2.nodejs 使用 node api
  • 应用层面
    1.前端js用于网页,在浏览器运行
    2.nodejs可用于服务端,如开发web server
    3.nodejs也可用于本机,webpack等本机工具
3.nodejs如何调试

1.启动nodejs服务时,使用inspect
2.代码中使用debugger断点
3.使用chrome调试 - chrome://inspect

4.当前文件和当前目录的路径,如何获取

1.__filename
2.__dirname
3.两个都是全局变量

5.commonjs和es6Module的区别

1.es6 Module是静态引入,编译时引入,所以必须放在最外层
2.语法不同
3.commonjs是动态引入,执行时引入
4.es6 module 是静态引入,编译时引入

6.path.resolve和path.join的区别

1.两者都是用于拼接文件路径
2.path.resolve获取绝对路径
3.path.join获取相对路径

7.时间循环event loop 在nodejs和浏览器的区别
  • nodejs中的异步
    1.setTimeout setInterval -宏任务
    2.Promise async/await -微任务
    3.process.nextTick - 微任务(微任务中最先执行)
    4.setImmediate - 宏任务
    5.I/O文件 网络 - 宏任务
    6.Socket连接,如连接mysql - 宏任务
  • 基本执行步骤
    1.执行同步代码
    2.执行微任务
    3.执行宏任务,回到第二步
  • nodejs中的异步特点
    1.微任务不多
    2.宏任务类型较多
    3.如果宏任务都放在一个callback Queue中,不好管理


    image.png
  • 每个阶段和微任务
    1.每个阶段结束之后,都要执行微任务
    2.微任务中,process.nextTick优先级最高,最早执行
    3.(但process.nextTick现已不推荐使用,因为会阻塞IO)
  • 几个细节
    1.settimeout比setImmediate执行更早
    2.process.nexetTick比promise.then执行更早
    3.另外,建议用setImmediate代替process.nextTick
  • event loop 在浏览器和nodejs的区别
    1.nodejs异步api更多,宏任务类型也更多
    2.nodejs的event loop分为6各阶段,要按照顺序执行
    3.微任务中process.nexetTick优先级更高
  • 关于nodejs版本
    1.新版nodejs已和浏览器趋同
    2.即,兼容代码在两者执行的结果是一样的
    3.网上很多资料都是旧版nodejs的,注意鉴别
8.async/await执行顺序问题
9.session如何实现登录?
  • cookie如何实现登录校验


    image.png

    前端登录完,服务端会设置一个cookie,把用户信息设置上给前端,在同域下,前端在请求其他接口的时候都会带上cookie(会触及到设置cookie的过期时间和安全性问题)

  • session和cookie的关系


    image.png

    cookie带了用户信息的,用户信息是敏感的,明文的话容易暴露,我们在用户信息里面把用户的标识带上如userId,这样前后端穿的是一个无意义的标识,服务端的session来处理对应标识.cookie是用户身份的记录,session是服务端,存储了记录和用户身份的对应关系.

  • session为何需要存储在redis中
    1.进程有内存限制
    2.进程的内存是相互隔离的
    3.存储到redis,可解决这些问题
10.描述koa2和express的中间件机制

1.从代码来看,中间件是一个函数
2.从业务来看,中间件则是一个独立的模块
3.模块拆分,模块流转,即可完成复杂的功能

  • express中间件实现
const http = require('http')
const slice = Array.prototype.slice

class LikeExpress {
    constructor() {
        this.routes = {
            all: [],
            post: [],
            get: []
        }
    }

    register(path) {
        let info = {}
        if (typeof path === 'string') {
            info.path = path
            // 从第二个参数开始,转换为数组,存入stack
            info.stack = slice.call(arguments, 1) //数组
        } else {
            info.path = '/'
            // 全部存入
            info.stack = slice.call(arguments, 0)
        }
        return info
    }

    use() {
        const info = this.register.apply(this, arguments)
        this.routes.all.push(info)
    }

    post() {
        const info = this.register.apply(this, arguments)
        this.routes.post.push(info)
    }

    get() {
        const info = this.register.apply(this, arguments)
        this.routes.get.push(info)
    }
    match(method, url) {
        let stack = []
        if (url === '/favicon.ico') {
            return stack
        }
        // 获取routes
        let curRoutes = []
        curRoutes = curRoutes.concat(this.routes.all)
        curRoutes = curRoutes.concat(this.routes[method])
        curRoutes.forEach(routeInfo => {
            if (url.indexOf(routeInfo.path) === 0) {
                stack = stack.concat(routeInfo.stack)
            }
        })
        return stack
    }
    // 核心的next机制
    handle(req, res, stack) {
        const next = () => {
            // 拿到第一个匹配的中间件
            const middleware = stack.shift()
            if (middleware) {
                // 执行中间件函数
                middleware(req, res, next)
            }
        }
        next()
    }
    callback() {
        return (req, res) => {
            res.json = (data) => {
                res.setHeader('Content-type', 'application/json')
                res.end(
                    JSON.stringify(data)
                )
            }
            const url = req.url
            const method = req.method.toLowerCase()
            const resultList = this.match(method, url)
            this.handle(req, res, resultList)
        }
    }
    listen(...args) {
        const server = http.createServer(this.callback())
        server.listen(...args)
    }
}

module.exports = () => {
    return new LikeExpress()
}
11.读取大文件 - 流 stream

1.1G大小的acess.log
2.分析其中Chrome浏览器的占比
3.考虑cpu和内存的限制

const fs = require('fs')
const path = require('path')
const readline = require('readline')
const filename = path.join(__dirname, '../', '../', 'logs', 'acess.log')
// 创建readStream
const redStream = fs.createReadStream(filename)
// 创建readline对象
const rl = readline.createInterface({
    input: redStream
})

// 初始化总访问数据 
let num = 0
// 初始化谷歌数据
let chromeNum = 0
// 开始读取
rl.on('line', readData => {
    if (!readData) {
        return
    }
    //记录总行数
    num++
    const arr = readData.split(' -- ')
    if (arr[2] && arr[2].indexOf('Chrome') > 0) {
        chromeNum++
    }
})
rl.on('close', () => {
    console.log('chromeNum:' + chromeNum)
    console.log('num:' + num)
    console.log('Chrome占比:' + chromeNum / num)
})

12.nodejs线上为何开启多进程(PM2)

1.高效使用多核CPU
2.充分利用服务器内存
3.最终:压榨服务器,不浪费资源

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容