当前位置: 首页 > Web前端 > JavaScript

全球顶级交易所前端双面后台

时间:2023-03-27 01:24:56 JavaScript

今天早上在脉脉看到一个关于BN的前端双面分享。作者纯粹出于目的分享了最近的一个面试问题。我觉得这是一套不错的面试题,分享给大家。为什么会有一套前端面试题,什么样的项目会用到这类面试题背后的知识?从0-1有幸参与了几个项目,比如:桌面IM项目(Electron、React、Node.js)、端到端加密、几个专注于聊天的大型SAAS系统(React)小程序拥有20万人(太郎)HybridAPP微信公众号一些web3项目(流量池千万级,solidityReactTypeScriptNode.js)等,其中一些需要一定的技术深度。它们背后的知识包括:通信、基于TCP的端到端加密长链路通信、安全、用户隐私、安全、Telegram-like性能:处理和展示大量数据、前端任务调度、重-rendercontrol等设计模式的理解和实践以及面向对象编程:如singletonMode、InversionofControl、DependencyInjection阅读和理解react和Vue的关键节点源码理解ES6异步实现理解浏览器渲染原理Node.jsLinux、docker、K8s、nginx等基础运维知识等等……这里没有展开,因为写这篇文章的时候中午没吃午饭。很饿,一般人根本不需要其他冷门知识。假设这样一个场景,比如每秒两个人同时给你发消息,你的客户端(前端)不需要做任务调度。如果一千个人同时每秒钟给你发很多消息,这个时候就需要进行任务调度,因为涉及到网络层、DB层、缓存层(前端内存,比如redux等),以及数据流和更新频率和时序控制。交易,同样的事情。例如,一种货币的价格在一秒钟内剧烈波动。由于IM场景和双工通信,您可能会在一秒钟内收到多个推送。这个频率如果按照用户的实际场景拆解细化,是一个极其复杂的需求。我不会在这里谈论它。这个时候,你会用到我上面提到的大部分知识。在做性能优化的时候,当你的知识足够全面和丰富的时候,其实更像是下棋。悔改。优缺点随着互联网的进步,我觉得前端会越来越像一个完整的客户端。现在有webContainer、webasm等技术。只要谷歌解决了native-socket和安全的一些关键节点问题,它就是完整的客户端。不需要Electron之类的。说说话题一,React的时间分片思想可以结合我三年前的一篇文章手写的mini-react源码。看一下https://github.com/JinJieTan/Peter-/tree/master/mini-React先看cpu调度时间片。时间片是CPU分配给每个程序的时间。每个线程都分配了一个时间段,称为它的时间片,也就是允许进程运行的时间,这样可以从表面上看每个程序。同时看。如果时间片结束时进程还在运行,CPU就会被拿走分配给另一个进程。如果进程在时间片结束前阻塞或结束,则CPU立即切换。而不会造成CPU资源的浪费。宏观上:我们可以同时打开多个应用,每个程序并行运行,同时运行。但从微观上看:由于只有一个CPU,一次只能处理程序的部分需求。如何处理公平性,一种方法是引入时间片,每个程序依次执行。那么react的时间片思想是什么?两年前,我们公司的一个项目,从react0.14升级到react16。记得当时给公司里的一些同事科普了一下。react16引入了fiber,其实这种时间分片的思想就是react16的fiber。当时react0.14版本的项目有个问题,就是会卡顿,因为在react16版本之前,更新是一口气完成的。如果这个过程很长,就会导致很长的等待(卡)时间。react16版本更新后,会有一个Reconciliation阶段。这个阶段会遍历虚拟dom树,找到更新的节点,完成一系列的操作。.这个阶段有很多计算,会长时间占用cpu。并且这个Reconcilation阶段是可以中断的(暂时挂起),这样浏览器就可以先响应高优先级的事件,比如用户交互。这就是所谓的时间分片思想,本质上就是任务调度2.为什么不用requestIdleCallback?我已经在代码中注释了,并且我已经测试了requestIdleCallback。用于任务调度的手写反应。原因是:requestIdleCallback的兼容性不好。对于频繁的用户交互和多次合并更新,requestAnimation更及时,优先级高,requestIdleCallback适合处理可以延迟渲染的任务。我们可以发现很多优化思路都来自操作系统本身的认知,对事物的认知决定了发展的天花板。useMemo的原理和优化原理背后,是通过Object.js的方法来遍历比较传入依赖的prev和current值。使用简单的对比,省去了renderreact不必要的副作用。比较笼统的问题,我不会回答这个问题。vue的nextTickvue2有一个优雅的退化过程。首先是promise.then然后是MutationObserver,然后是setImmediate,最后是setTimeoutlettimerFunc//nextTick异步实现fnif(typeofPromise!=='undefined'&&isNative(Promise)){//Promisesolutionconstp=Promise.resolve()timerFunc=()=>{p.then(flushCallbacks)//包装flushCallbacks输入Promise.then}isUsingMicroTask=true}elseif(!isIE&&typeofMutationObserver!=='undefined'&&(isNative(MutationObserver)||MutationObserver.toString()==='[objectMutationObserverConstructor]')){//MutationObserverschemeletcounter=1constobserver=newMutationObserver(flushCallbacks)//使用flushCallbacks作为cbconst来观察变化textNode=document.createTextNode(String(counter))//创建文本节点//观察文本节点变化observer.observe(textNode,{characterData:true})//timerFunc改变文本节点的数据触发观察回调flushCallbacktimerFunc=()=>{counter=(counter+1)%2textNode.data=String(counter)}isUsingMicroTask=真}elseif(typeofsetImmediate!=='undefined'&&isNative(setImmediate)){//setImmediate方案timerFunc=()=>{setImmediate(flushCallbacks)}}else{//最终降级方案setTimeouttimerFunc=()=>{setTimeout(flushCallbacks,0)}}这个问题是想知道面试官是否真正了解Vue框架的数据更新-渲染异步,而不仅仅是这个nextTick。剩下的宏任务和微任务可以配合第六题的答案一起使用。什么是InversionofControlandDependencyInjection这个问题说明面试官比较喜欢这种风格的模型,不然也不会问这个特别的问题,但是需要注意的是,他既然问了这方面,肯定会展开发散。问你Practicalusage和其他designpatterns之类的。所以背面试题对于稍微高一点的面试是靠不住的。个人反对back-to-back的面试题,更看重过往项目经验和基础知识的掌握和实践思维InversionofControl(IoC):在单一职责原则的设计下,能完成的任务很少由一个对象。大多数任务需要多个对象进行协作,因此对象之间存在依赖关系。一开始,对象之间的依赖关系是自己解决的。当需要一个对象时,使用一个新的对象,控制权在对象本身。但是这种方式的耦合度很高。一个对象的一个??小修改就可能引起连锁反应,需要一路修改依赖的对象。经典的控制反转(IoC)原则:上层模块不应该依赖下层模块,它们都依赖于一个抽象,抽象不能依赖具体,具体必须依赖抽象。在TypeScript中,上面这句话可以理解为多个类遵循一个接口,这些类对应的数据值不同,但是字段和类型是相同的。当需要单独或组合使用时,可以直接使用这些类来控制反转。此时的好处:如果以后要更新进化,只要新的接口兼容已有的接口,不需要改动已有的类代码来做兼容。这就涉及到Ts的协方差和求逆。有兴趣了解一下依赖注入(DI—DependencyInjection):对象之间的依赖关系是交由外部进行管理的,但是如果组件之间的依赖关系是由容器Runtime决定管理的,形象地说就是容器动态注入某种依赖关系到组件,比如react的Context,使用Context.Provider注入数据比如装饰器@Foo()智能合约内部也有装饰器,比如访问修饰符onlyOnwer(){require(msg.sender==onwer,'msg.sendernotonwer');__;}function_mint()publiconlyOnwer(){//dosomething}控件中的依赖注入,本质上有助于简化依赖的组装过程。asyncpool实现前端并发控制库asyncpolES7实现版本asyncfunctionasyncPool(poolLimit,array,iteratorFn){constret=[];//存储所有异步任务constexecuting=[];//存储正在执行的异步任务for(constitemofarray){//调用iteratorFn函数创建一个异步任务constp=Promise.resolve().then(()=>iteratorFn(item,array));ret.push(p);//保存新的异步任务//当poolLimit值小于等于任务总数时,进行并发控制if(poolLimit<=array.length){//当任务完成时,移除完成的任务来自正在执行的任务数组conste=p.then(()=>executing.splice(executing.indexOf(e),1));执行.push(e);//保存正在执行的异步任务if(executing.length>=poolLimit){awaitPromise.race(executing);//等待更快的任务执行完成}}}returnPromise.all(ret);}ES6实现版本:functionasyncPool(poolLimit,array,iteratorFn){leti=0;constret=[];//存储所有异步任务constexecuting=[];//存储正在执行的异步任务constenqueue=function(){if(i===array.length){returnPromise.resolve();}constitem=array[i++];//获取新的任务项constp=Promise.resolve().then(()=>iteratorFn(item,array));ret.push(p);让r=Promise.resolve();//当poolLimit值小于等于任务总数时,进行并发控制if(poolLimit<=array.length){//当任务完成时,从执行任务数组中取出完成的任务conste=p.then(()=>executing.splice(executing.indexOf(e),1));执行.push(e);if(executing.length>=poolLimit){r=Promise.race(executing);}}//执行任务列表中较快的任务完成后,才会从数组中获取新的待办任务returnr.then(()=>enqueue());};returnenqueue().then(()=>Promise.all(ret));}总结面试题比较接近实际,感兴趣的是框架原理和前端异步和基础考察。这些知识点与框架开发中复杂功能的调试密切相关。学习源码是不可或缺的进阶过程。那个时候可能学了也没用,但是当你真正理解了本质之后,你会发现大部分优秀的框架源码都是大同小异的,包括它们的使用,思路和概念等等,源码最重要的是在你需要的时候帮你使用它以便将来调试复杂的场景。当然这些都是建立在自己很久没有更新的前端知识的认知基础上写的。如果有什么问题,欢迎大家指出。写于2022年5月31日,写智能合约的web2.5软件工程师如果觉得不错,可以点个赞,帮我关注公众号:前端巅峰