快手一面面试
今天主要是面快手的一面,小哥哥人超好,也给了我很多指导,接下来不要说感情了,梳理一下任务,在编码的时候,被推荐了ESlint、prettier去做编码规范的工作。Eslint用过了,立马增加插件prettier。前辈和我说有问题要深入,深入的了解一些优缺点和好处。(虚拟滚动)
下述有关css属性position的属性值的描述,说法错误的是?
CSS中Position属性有四个可选值,它们分别是:static、absolute、fixed、relative。
◆position:static 无定位
该属性值是所有元素定位的默认情况,在一般情况下,我们不需要特别的去声明它,但有时候遇到继承的情况,我们不愿意见到元素所继承的属性影响本身,从而可以用position:static取消继承,即还原元素定位的默认值。
◆position:absolute 绝对定位
使用position:absolute,能够很准确的将元素移动到你想要的位置,
◆position:fixed 相对于窗口的固定定位
这个定位属性值是什么意思呢?元素的定位方式同absolute类似,但它的包含块是视区本身。在屏幕媒体如WEB浏览器中,元素在文档滚动时不会在浏览器视察中移动。例如,它允许框架样式布局。在页式媒体如打印输出中,一个固定元素会出现于第一页的相同位置。这一点可用于生成流动标题或脚注。我们也见过相似的效果,但大都数效果不是通过CSS来实现了,而是应用了JS脚本。
请特别注意,IE6不支持CSS中的position:fixed属性。真的非常遗憾,要不然我们就可以试试这种酷酷的效果了。
◆position:relative 相对定位
所谓相对定位到底是什么意思呢,是基于哪里的相对呢?我们需要明确一个概念,相对定位是相对于元素默认的位置的定位。既然是相对的,我们就需要设置不同的值来声明定位在哪里,top、bottom、left、right四个数值配合,来明确元素的位置。
1、promise和async/await 优缺点好处
优点
:
- async/await 做到了真正的串行同步的写法,代码阅读相对容易。
但是javascript的90%都是在异步的场合都是ajax,ajax就一定要考虑异常,很可能需要try…catch来处理异常。
- 对于条件语句和其他流程的语句比较好,可以直接写在判断条件里。而且await a()没有出错的可能性,还可以省掉try…catch
1 |
|
- 在处理复杂流程时,在代码清晰度方面有优势
如果有这样一个业务场景:一个数组变量,如果它的length大于0,就遍历它进行下一步操作,如果length等于0,说明没有经历过ajax请求,则先ajax请求并赋值内容,然后再遍历它进行下一把操作;如果ajax的结果依旧为空,则显示toast,并中断流程。
1 |
|
如果我换成async/await呢?
1 |
|
Promise写法,必须有if(arr.length){resolve();}
,而async/await不必考虑这个分支。
Promise写法的代码不仅冗长,而且这还是在省略了一部分代码的前提下,showToast('数据为空')
这个分支永远是pending状态,可能会带来一些问题。
特点一:
async/await无所谓优缺点的特点一:无法处理promise返回的reject对象,要借助try…catch…
1 |
|
则await g()
会直接报错,必须使用try…catch…捕获。
那么假定有3个ajax串行请求,Promise模式与async/await的对比如下:
1、允许统一处理reject的话:
Promise(伪代码):
1 |
|
async/await(伪代码):
1 |
|
对比结果:从代码量上说,大同小异,就看你是否用的惯try…catch….。
为什么说用的惯呢,看这段代码,这段代码在上文粘贴过,想象一下,假如if ( await a () === 222)
,{}
里的内容有20行,会怎样——你会发现,try
和catch
相距22行,很远,很难阅读,并且,内容体里面如果还有try…catch…怎么办?这就成了try…catch…的嵌套圣诞树,更加难以阅读,最终解决办法只能是:如果if的内容体太长,尤其是try…catch…的嵌套圣诞树,就放弃if(await a() === 222)
这种优雅的写法,改成const res == await a()
;这种写法,然后把这句单独做try…catch…。
特点二
:Promise可以轻松做到并行:
1 |
|
但是await做不到,它一定是阻塞的。await甚至可以阻塞for循环:
1 |
|
注意:
await做不到并行,不代表async就不能并行。只要await不在同一个async的函数里就可以并行。
比如:
1 |
|
特点三:
async/await全局捕获错误必须用window.onerror,不像Promise可以专用window.addEventLister('unhandledrejection' , function)
,而window.onerror会捕获各种稀奇古怪的错误,造成系统浪费。
尽管window.onerror的开销大,但是一个成熟的系统是一定要利用window.onerror做错误监控系统,所以,无所谓了。
async缺点一:
try…catch内部的变量无法传递给下一个try…catch
Promise和then/catch内部定义的变量,能通过then链条的参数传递到下一个then/catch,但是async/await的try内部的变量,如果用let
和const
定义则无法传递到下一个try…catch,只能在外层作用域先定义好。
async缺点二:
async/await无法简单实现Promise的各种原生方法,比如.race()之类
如果真的要编写一些工具库,确实可以实现Promise的各种原生方法,但是放着Promise原生方法不用,却要写工具库,完全没有必要。
什么时候用什么呢?
1.需要用到promise各种便捷的方法(比如。race()之类)的时候,一定用Promise
2、并行的请求最好用Promise
3、不需要并行的场合,如果要传递参数,最好用Primise
4、其他ajax场合,看你喜好决定try…catch,还是.catch()
额外讨论:ajax异常全部用拦截器处理,是否可以避免使用try…catch?
拦截器对于后端业务代码错误,例如500错误,应当怎么处理呢?
如果:拦截器把200和500都归类为resolve
优点:
共同的好处是只需要考虑200的状态,所以确实不需要写try…catch,也不需要.catch()
缺点:
对两个方案都有缺点,500归为resolve的话,语义比较拧巴,而且业务代码永远需要这种代码:
1 |
|
如果:拦截器只将500错误归为reject,而200依然属于resolve
优点:
共同的好处是不用一遍遍的写if(res.code ===XXX)
,因为try里面是200的处理代码,catch里面是500的处理代码,天然就分开了。而且,500错误归为reject,从语义上说不拧巴。
缺点:
对两个方案都有缺点,必须用try…catch或.catch()
捕获reject,不能省略。
2、数组的浅复制可以如何做?有哪些方法?
给我谈了几个array的方法
3、项目的优化方面,提了个建议:使用虚拟滚动来优化文件树
4、拍平对象
1 |
|
补充数组扁平化:
1 |
|
5、数组浅拷贝的方法
序号 | 方式 | 例子 | 说明 |
---|---|---|---|
1 | concat | let res = arr.concat(); | 连接数组返回一个新数组 |
2 | slice | let res = arr.slice(); | 返回选定的元素默认从0开始到结尾 |
3 | 解构 | let res = […arr]; | 创建了一个新的数组赋值为当前数组的值 |
4 | 装x写法 | let […res] = arr; | 同上 |
5 | map | let res = arr.map(i=>i); | 遍历数组逐个返回元素给res |
6 | Array.of | let res = Array.of(…arr); | 该方式将一堆数字转化成数组返回 |
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!