人生中第一次面试!袋鼠云nodejs岗

3.4袋鼠云nodejs岗面经 2h03min

1.自我介绍

2.拷打项目,一个一个拷打

● 第一个系统 oss对象存储平台

1.讲讲做的是个什么业务

2 .这里的对象存储具体值得是什么

3.有没有真的实现OSS对象存储

4.项目技术上遇到了什么困难怎么解决的

5.讲讲文件上传分片上传断点续传等;

6.现在回过头看觉得这个项目有什么缺点和改进的点;

● 第二个项目 面对hr的简历分析系统;

1.介绍这个系统的业务;

2.讲讲流程管理模块

3.讲讲数据大屏(开了屏幕共享对着项目截图讲)

4.打开项目框架怎么构思的。

● 第三个项目:

预科志愿分流系统:问了vuex在项目中的运用

● 项目都要求运行展示了,看了代码细节

3.用过哪些js函数库(axios,jquery)

4.了解哪些项目开发设计中的一些规范

5.数据库中事务的四大特性(原子性,隔离性,持久性,还有个一致性忘了)

6.问是否了解redis(没有,过了)

7.问了解哪些数据结构(答了栈,队列,链表,树,图,堆)

8.问数组和链表的区别(答了,数组内存连续,大小固定,延申讲了数组的扩容原理是创建一个更大空间的数组将原数据移动进去;链表内存分散,不固定;讲了数组删除和添加需要进行挪动,但链表只需要改变指针指向更加灵活;)

9.接着上一问,问了数组和链表读取数据的区别(答了数组通过下标直接读取,而链表需要遍历到目标数据上)

10.问了系统中内存为什么能够随机访问(没答出来)

11.列举一下线程的同步方式(只讲了互斥锁和信号量)

12.讲讲JS的事件循环

13.给了一道题目要求输出结果(当时一紧张不记得怎么去看了,明明前几天刚复习过,一紧张嘴巴乱讲话把settmeout说成了是微任务。说明还没理解透彻,没回答正确,但在hr的提示下梳理好了思路)

setTimeout(() => {

console.log('1')

Promise.resolve(2).then(val => {

console.log(val)

})

}, 0)

setTimeout(() => {

console.log('3')

}, 0)

Promise.resolve(4).then(val => {

console.log(val)

})

Promise.resolve(5).then(val => {

console.log(val)

})

console.log('6')

答案是645123

14.问什么是完全二叉树

15.场景题:在一个音乐播放软件中,需要实现统计有多少个用户播放过某一首歌

(一开始说了一个很基础的实现,就是点击播放时将用户id和歌曲id存到数据库中,如何通过sql语句去重查询

然后要我写出查询的sql语句,写出来了,一不小心把count写成了sum😅,hr提醒了我,我才反应过来服了)

后面在hr的提示说第一种方法的问题是数据量太大,所以你需要思考如何压缩需要存储的数据量

然后就说了另一种实现方法,就是设置一个标识属性标志用户是否播放过该首歌,如果播放过就不需要重复存储数据。

后面问有没有更好的实现方法,后面想着是不是用哈希表,但是刚想说,hr就说没事这个问题先过了

16:讲讲osi七层模型,并讲讲每一层的作用和涉及的协议

物理层:(答:和选用什么物理传输介质相关,比如光纤电缆之类的,协议不知道没说)

数据连路层(答:主要作用是校验错误,提供可靠传输,协议忘了没说)

网络层(答:最经典的就是IP协议,在网络中传输包,其中还涉及到路由器转发之类的)

传输层(答:经典协议TCP和UDP分别表示可靠传输协议和不可靠传输协议,作用没讲清楚,磕绊了半天说是负责端到端是数据传输)

会话层

表示层(答:不太记得会话层和表示层的作用了)

应用层(答:主要就是和用户的一些交互比如页面显示之类的,设计HTTP等协议)

17.浏览器输入url到展示之间发生了什么

这个问题比较幸运,面试前半个小时刚给朋友讲了一遍这个过程。

先是回答:浏览器先解析URL,然后将域名转化为IP,转化IP过程要先查看缓存是否存在,没有就要进行DNS查询

这里hr问:是哪里的缓存(回答了浏览器的缓存)

然后继续说:得到了IP之后就要进行三次握手建立客户端与服务端之间的TCP连接

然后继续说:接下来就是客户端向服务端发起请求,这里我延申讲解了协商缓存和强制缓存,巴拉巴拉然后客户端获取到数据了

然后继续说:客户端获取数据之后要进行渲染,渲染的过程就是先解析html生成dom树,再解析css样式表获得css样式树,然后结合他们俩生成渲染树,然后根据渲染树进行布局和绘制,将页面显示在屏幕上。

18.场景题:实现一个二维码的扫码登录。是否有做过这个业务,如果没有的话,从技术员的角度想想如何实现。

先思考了一下,想到了之前做的业务里有登录注册时发送验证码的业务,然后感觉应该原理差不多,试着讲了

回答:没有做过二维码的业务,但是我觉得应该和我之前做的验证码验证的差不多的原理,因为验证码和二维码的一个主要应用场景就是验证身份。我当时写验证码时,是先在服务端生成一串数字,然后通过邮箱等方式发送给客户,如果客户输入的验证码传个后端进行校验成功就可以成功登录。然后二维码的话,因为我们常识知道扫描二维码之后是会解析出一些数据的,这就包含比如说身份数据之类的。我觉得二维码可能就是也是服务端先通过一些第三方库生成二维码图像以及一个类似于标识符的东西,然后客户扫码之后就能解析出一些内容,服务端再进行校验就可以了。

然后说完,hr补充问题,说,你这还没有讲完呀,我们需要的是一个完整的流程,服务端校验之后要怎么让客户端知道验证成功了然后继续下一步操作呢?

hr这句话提示了我,我在思考的时候就想起了前几天刚复习的websocket,然后回答:这里的话是需要服务端给客户端一个响应告知验证成功的,然后这里因为axios的功能呢(胡说八道什么呜呜),服务器没办法主动向客户端发送响应,所以需要用到websocket来实现主动向客户端发送验证结果的请求。

这里提到了websocket,hr就说可以过了这道题

19.在业务中如何获得客户端的真实ip

这个我不知道,但是提出了基于这个问题自己的思考,讲了在获取过程中要考虑到一个安全性的问题,比如说可能会接收到假的ip地址之类的。

然后hr说服务端在接受了数据并进行处理之后通常是要发出一个响应的,如果这个ip是假的,服务端就发不出去,所以几乎不需要考虑这个问题。然后hr说,在你现在比如说你是在学校吗,你所在的校园网,你自己其实并没有一个完全属于你自己的ip地址,那么如果说我们在一个假想的完美环境下,客户端和服务端都在公网中有ip地址,请问我的服务端能够获取到客户端的ip地址吗?

我回答说可以的,因为他们都在公网中可以查询到。

然后hr提示我说还记得ip的报文结构吗?

我说我不太记得了,只记得有源IP地址和目的IP地址之类的。

然后hr说对呀,所以说ip报文数据中存储了源IP地址肯定是能获取到的对吧。(这里才恍然大悟 刚才没想清楚,还是计算机网络忘了很多东西,需要加强),然后给我讲了一下如果如果源ip地址是假的会怎么样。

这里我脑子有点混乱没讲上来,这个问题就过了。

20.问了一下是否了解nat(没有)

21.好像还问了啥 忘记录音了!!忘记了

21.说明公司是不支持远程办公的,问我这边情况如何?

我说之前学长学姐也有大三直接出去实习的,学校的课程只需要完成作业就行。

22.反问环节

● 问了后面的面试流程是什么样的 /还有一轮技术面和hr面

● 问了公司是否是全栈;/否

忘记录音了,还有一些问题不记得了,后面想起来再补充

补充

● 还问了最近在学习些什么新东西

答的nginx和docker,但是是最近刚开始入门的,所以后面说讲讲docker的时候没讲什么

● 还问了是否了解面向对象编程

我回答了java的面向对象编程原理,讲解了封装继承多态

● 还问了是否学习了typescript

回答没有学,但是正计划学了

● 问学习了设计模式之后对你有什么帮助吗

举例了vue的双向数据绑定中观察者模式的运用

全部评论
哦哦是nodejs岗,我是说怎么好像和前端有关系但是我都不太清楚呢😂😂笑死,那还是好厉害,你前后端都会
点赞 回复 分享
发布于 05-21 23:15 陕西

相关推荐

码农烧烤启动:我还还有一个朋友😂 是个学院本,毕业是比较早 以前很容易找到工作 他厉害的地方在:即使找到工作了依然保持每个月一次或几次面试 然后复盘总结抓住好机会就往上跳了 今年不知道跳哪去了 总而言之,成了程序员就得持续面试和学习 尤其是现在这个🐢环境下 可能前脚入后脚给你裁了 不一定要频率非常高 就像一场马拉松 你人生还这么长嘞…… 所以不用内耗 春招不行就社招嘛,没有经济来源就干干收银员,烧烤啥的,有人看不起你别管啊,这是你自己的剧本,你说谁杀青就杀青了🙂 没人的时候不也可以学学😂 偶尔来次面试 不爽就辞职换一家 你的人生是为自己而活
点赞 评论 收藏
分享
对CPU、寄存器、缓存、内存的大概了解:一般市场上的CPU和寄存器、缓存封装出售,CPU每次都要在寄存器存取,寄存器是个临时存取空间,寄存器去访问CPU,在寄存器和CPU之间有个缓存(cache),将常用的数据存到缓存上,缓存有三级缓存(1、2、3),价格和速度依次降低。寄存器要获取的变量能不能在缓存中获取到就涉及到命中率问题,如果获取不到,就直接从内存去拿。栈区:存放函数的参数值、局部变量等,由编译器自动分配和释放,通常在函数执行完后就释放了,其操作方式类似于数据结构中的栈。栈内存分配运算内置于CPU的指令集,效率很高,但是分配的内存量有限,比如iOS中栈区的大小是2M。堆区:就是通过new、malloc、realloc分配的内存块,编译器不会负责它们的释放工作,需要用程序区释放。分配方式类似于数据结构中的链表。在iOS开发中所说的“内存泄漏”就是堆区的内存。静态区:全局变量和静态变量(在iOS中就是用static修饰的局部变量或者是全局变量)的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后,由系统释放。常量区:常量存储在这里,不允许修改。代码区:存放函数体的二进制代码。类型说明符:类型说明符 void、char、short、int、long、signed、unsigned、float、double、struct、enum、union。存储类型 extern、static、register、auto、typedef(变量有且只能有一个限定)。类型限制符 const(只读)、volatile。对变量的理解:extern:用在全局变量上表示该变量在其他文件中已经定义;用在函数上作用同全局变量。static:用在全局变量上,和非静态全局变量相比,限定了作用空间;用在局部变量上,把局部变量存到了静态存储区,延长了变量生存空间;用在函数上表示仅限当前文件使用。register:将频繁使用的变量放到通用寄存器中,避免频繁访问内存,直接从寄存器中取值,提高CPU的工作效率;注:只能将局部变量或形式参数定义为寄存器变量,一般较短的变量类型适合定义为寄存器变量,如short、char等。auto:C语言变量缺省存储类型就是auto。typedef:给变量或变量表达式换一个别名。const:只读变量;但是能通过指针去修改局部const变量,const变量是一个编译期间的常量。volatile:1. 易变性;所谓的易变性,在汇编层面反映出来,就是两条语句,下一条语句不会直接使用上一条语句对应的volatile变量的寄存器内容,而是重新从内存中读取。volatile的这个特性,相信也是大部分朋友所了解的特性。2. “不可优化”特性。volatile告诉编译器,不要对我这个变量进行各种激进的优化,甚至将变量直接消除,保证程序员写在代码中的指令,一定会被执行。3. C/C++ Volatile变量间的操作,是不会被编译器交换顺序的。(中断、多线程)。C程序的内存分配:堆、栈、静态存储区、文件分配区(常量字符串)、程序分配区(二进制代码)。sizeof与strlen:sizeof是关键字,对于数组来说就是申请的长度,对于指针来说就是4/8(看系统位数)。strlen对于字符串来说,就是计算‘\0’之前的长度。函数的参数传递:值传递,引用传递,指针传递,数组地址传递。Const、指针、int/char等组合的意义:const int x:表示变量只读,不可更改。const char * x/char const *x:声明该指针变量指向的是常量,即该指针变量的内容可以改变,但是该内容指向的内容不可改变;如:const char *x = “helloworld”;可以直接更改x,如x = ”hi“就可以成功,但更改x[0] = ‘u’就会失败。char *const x:声明该指针变量为常变量,即指针变量里面的内容不可改变,但是该内容指向的内容可以改变;const char *x = “helloworld”;不可以直接更改x,如x = ”hi“会失败,但更改x[0] = ‘u’就会成功。const char *const x:声明该指针变量里面的内容不可改变,同时该内容指向的内容亦不可改变。数组和指针:sizeof的用法,占用内存(连续\不确定),物理地址和逻辑地址。物理地址:加载到内存地址寄存器的地址,内存单元的真正地址;逻辑地址:CPU所生成的地址。Linux进程间通信:有几种方式:管道(pipe)、信号量、消息队列、信号、共享内存、套接字。strcpy和memcpy区别:strcpy只能复制字符串,memcpy能复制任何内容,memcpy会指定复制长度。内存泄漏和内存溢出:内存泄露是指申请的内存没有释放,导致可用内存越来越少;内存溢出指程序要用的内存大于可用的内存,如数组的使用,strcpy的使用。switch的变量允许哪些类型?不允许哪些类型?整形、bool、字符、枚举;不允许字符串等非基本类型。怎么防止头文件重复调用导致的编译问题:在头文件中添加#ifndef变量 /#pragma once。实时操作系统有哪些?怎么理解?路由器用的什么操作系统?FreeRTOS、Ucos。指针数组和数组指针,双重指针:对指针数组来说,首先它是一个数组,数组的元素都是指针,也就是说该数组存储的是指针,数组占多少个字节由数组本身决定;而对数组指针来说,首先它是一个指针,它指向一个数组,也就是说它是指向数组的指针,在32位系统下永远占4字节,至于它指向的数组占多少字节,这个不能够确定,要看具体情况。指针数组如char *x[10],指向数组的指针,如char *x[10]={“hello”,“world”};x[0]=“hello”,x[1]=“world”。数组指针如char (*x)[10],表示指针x指向char [10]数组,为匿名数组。双重指针如char **x。结构体自增的含义,双重指针自增:自增从右向左进行。寄存器怎么用,怎么操作?保存一些经常调用的数据,不再访问内存。怎么获取全局变量和局部变量的地址?(gdb)backtrace bt。进程中的同步、异步怎么用?同步一般通过同步锁实现;同步锁和自旋锁区别:一种是没有获取到锁的线程就一直循环等待判断该资源是否已经释放锁,这种锁叫做自旋锁,它不用将线程阻塞起来(NON-BLOCKING);还有一种处理方式就是把自己阻塞起来,等待重新调度请求,这种叫做互斥锁。进程和线程的关系和区别?进程:进程是能在系统中独立运行并作为资源分配的基本单位,是CPU分配资源的最小单位,它包括独立的地址空间、资源以及一至多个线程。线程:线程是进程中的一个实体,是CPU调度的最小单位。树的遍历(递归&&非递归):如利用中序遍历,左子树-根节点-右子树,根据堆栈的push和pop进行进栈和出栈的操作。嵌入式C++面经推荐大佬面经  链接在下边  c++/嵌入式面经专栏-牛客网 https://www.nowcoder.com/creation/manager/columnDetail/MJNwoM
点赞 评论 收藏
分享
4 11 评论
分享
牛客网
牛客企业服务