小皮筋

小皮筋 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织 www.ephemeron.top 编辑
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 该用户太懒什么也没留下

个人动态

小皮筋 回答了问题 · 9月5日

antd form 当Form.Item包含的不是antd组件时,setFieldsValue不起作用,怎能处理?

Form.Item 包装后,会给 children 添加 value 和 onChange 属性,只需要在 ReactQuill 组件中接收 value 属性进行回填,后续更改通过 onChange 触发表单即可。

关注 2 回答 1

小皮筋 收藏了文章 · 2019-10-08

大前端时代,浅谈JavaScript开发重型跨平台应用以及架构

clipboard.png

大前端时代以及即将到来的5G时代,3D可视化,音视频直播技术,IM即时通讯场景应用我觉得都是大有可为的。前段时间爆款换脸应用出现,到近段时间头像加🚩的火爆,这是好事。

不知不觉,九月就要过去,由于这个月工作上,被C++折磨得很难受,而且其他时间都在学习,所以没有时间写文章,好在技术提升很大。今天准备好好谈一谈重型应用的架构以及技术选型,为接下来我的正式架构设计做个铺垫。

为什么写重型应用的架构和技术选型

  1. 传统的web前端,只能发个ajax请求,画画页面。了不得写个webApp
  2. 想让后端的同学们,了解下目前大前端的世界,现在的前端跟以前不一样了,特别现在市场很缺高级前端,但是术业有专攻,这点我承认
  3. 大前端的定义,太广泛,在我看来,必须深入前端某个方向,以及能独立设计不那么复杂场景下的后端架构。
  4. 在极客时间上提问了winter老师,我自我感觉已经良好,但是迷茫了。他回怼了我:想一想你用你的技术做出了什么nb的东西把。
  5. 是人都想做出点什么事情,我想引起大家的共鸣去使用某些技术,或者朝着这个方向去发展,共同提升 社区的技术整体层次

什么是重型应用

例如微信,QQ,Telegram, 以及一些工具类的应用

说到这些大家肯定觉得,为什么不说是游戏? 当然游戏也算,可是我相信做出1000万人每天都在用的产品是大家的梦想,起码能吹一辈子吧

工具类的东西其实是最难做的,比如vsCodeExcelPhotoShop这些。这也是为什么这么多年出现成功的工具类产品这么少。这里不得不提到vsCode,它其实就是用ELectron开发,基于TypeScript。当然肯定使用了不少C++插件,说到这里,留下伤心的眼泪,最近也是被折磨得很难受

成功开发一个重型应用的好处

  1. 出去面试基本上很容易成功,特别是专业性强的岗位,例如你在QQ开发了十几年,你根本不用出去找工作,当然你应该也不会跑
  2. 技术全面,复杂场景你都能hold
  3. 有能吹的地方,可以跟谁说:我开发的东西,多少万人在用,老了还能吹。 程序员嘛,一半时间都在吹水,还有接近一半时间在划水,只有一丁点时间在写代码
  4. 更容易财务自由,生活自由,例如现在很多有过成功的重型应用开发者已经不单纯靠代码产出维持生活。他们做技术顾问,卖课程,出书,办培训都甚至比单纯写业务代码赚得多很多

正式开始

  • 目前跨平台框架,移动端比较成熟的是React-native,但是大家有所了解的都应该知道,这个框架虽然生态比较成熟,但是在面对众多手机的适配难度,以及性能方面存在的缺陷,如果用它制作重型应用我觉得是不合适的,如果要做重型应用,移动端应该使用原生。
  • 库克说过,中国的移动端开发确实很强,美国人要做一个应用,首先考虑的是PC桌面端,而国内首先考虑的是移动端。
国内移动端开发人员,在我看来已经人目前已经够多了,如果说你现在不会React-nativeFlutter,我也不建议你去深入学习,特别是Flutter.

为什么要这么说?

React-native刚出来的时候,坑多吧。现在Flutter也是,可是当你从RN最初的版本踩坑踩到现在,之前踩的坑大都没有意义(说这些话想过被喷,但是...此处省略一万字,建议去了解下原理和基本使用,不要耗费太多时间)

一个技术你去使用,并不是它多流行,只要它足够流行。 ---来自某位国内大佬

技术的学习,应该多往底层钻研,如果你走错了路,钻错了方向,浪费了时间得不偿失,我之前有说过,前端最核心的几个基础知识点,应用层的东西从来不会很难。前提你的基础足够扎实

前端20个真正灵魂拷问,吃透这些你就是中级前端工程师 【上篇】

前端20个灵魂拷问 彻底搞明白你就是中级前端工程师 【中篇】

前端20个灵魂拷问 彻底搞明白你就是中级前端工程师 【下篇】

这些文章很多同学应该都看过,争议也很大,在我现在看也写得很烂,但是它里面的知识点是够的。当然你必须要去结合起来,然后深入学习每个知识点。

既然说了移动端没有合适的重型跨平台应用开发框架,那么只有PC端了。还有多少小伙伴在PC端开发呢?

Electron开发,来了

clipboard.png

我不止一次提到过这个框架,我觉得它真是一个非常棒的框架,为什么这么说呢?

  1. 我跟很多朋友说过,如果想开发APP,不会写原生,那么你肯定达不到某种境界。因为你始终有很多很多的黑盒过程,可是Electron就会大大降低这个概率。
  2. 基本上没有适配和差异性,linuxMac以及Windows三者都可以运行,除了Mac上某些特殊场景需要自己设计下菜单快捷键之类,以及一些文件IOMAC默认行为
  3. 最新的Node版本、运行的V8环境以及最新的谷歌浏览器一起被打包,最新的技术和API都可以用,无需适配担心兼容性,真正放飞自我,可以随时随刻用Node.js实现功能,甚至调用大量C++插件,著名的VSCode就是这样而来

clipboard.png

你甚至可以看成Electronweb网页套上一层壳,你可以在主进程写你的Node.js去实现功能,渲染进程你怎么写怎么写,还可以呼叫封装好的原生接口。遇到特别复杂的需求,用C++插件去实现吧

最终打包出来的安装包跟正常的桌面应用是一样的,正常安装卸载等,都已经封装好。

clipboard.png

目前GitHub上已经有77.2Kstar

应用层面的东西,大都不会太难,Electron的文档已经非常全面,基于它出现了很多复杂,而且成功的工具类重型应用。我相信它

clipboard.png

whatsApp也是基于它,国外还有一些很NB的应用也是。这里不做过多阐述,可以确定它是一个成熟而且成功的框架

可能很多人看到这里又要说标题党了,别急,下面来干货。

重型应用架构注重的核心问题

  1. 项目本身的最重要功能是什么
  2. 项目本身出发点是为客户提供什么方便
  3. 项目的核心竞争力是什么
一个好的开发,它一定能懂一些产品,甚至测试,当然他也应该会炒河粉,35岁以后好维持生活

我们今天举一个例子,IM,即时通讯,Telegram,20万人超级群端到端加密的核心卖点产品

clipboard.png

电报Telegram

clipboard.png

现在回答上面三个问题:

项目本身的最重要功能是什么

答案:即时通讯,信息的收发

项目本身出发点是为客户提供什么方便

使用产品进行消息传递

项目的核心竞争力是什么

20万人的超级群,端到端加密,隐私足够安全

核心竞争力,往往代表了这个应用产物的技术最难点,因为谁都能做,那么就不是核心竞争力了

所以我们其他的都忽略,关注第三点,开始进行技术选型,架构。

单线程的Node.jsJavaScript重型应用架构设计

要想写好这个架构,我觉得你首先在自身的擅长领域不能有太多的黑盒过程。例如框架源码,库原理实现,浏览器和Node.js的事件EventLopp以及他们的缺陷,你要熟知在心。因为像这种应用,一个小方向可能就会掏空你的技术栈,耗尽你的精力,例如音视频、图片处理等。

单线程的Node.js以及js主解析引擎,让我们又爱又恨。

这款应用的核心竞争力,是20万人超级群,那么数据量很大,大批量渲染压力和频繁加解密计算耗时、频繁数据库写入压力都是不可避免的,那么我们的Node.js擅长异步非阻塞,以及前端渲染进程的异步就显得尤为重要

前端架构整体的核心除了技术选型以及大体框架外,就是任务调度。

这里的任务调度分两种:

1.渲染任务调度

2.非渲染任务调度

单个渲染任务调度

1.React框架中,多次传入对象,setState会自动合并到一次执行,其实就是一种节流思想

2.ReactFiber架构思想,把若干个任务分割成多个小任务执行,中间根据你的任务优先级安排去选择时机执行

clipboard.png

3.淘宝的分片渲染方案,跟上面第二条有一些类似
clipboard.png

我之前说过,应用层的东西都不难,只要你基础足够扎实,能手写出简单的框架,以及库。你绝对能非常轻松应对前端百分80以上的性能问题和需求,技术最终都是相似的

上面只是说了别人的一些比较简单的优化方案,下面才是开始我们自己的渲染任务调度:

clipboard.png

回到我们的Telegram架构设计方案:

渲染任务架构过程需要着重考虑的几个问题:

1.渲染数据量特别大

2.更新特别频繁

3.尽可能手动回收垃圾,避免消息量过大,v8垃圾回收的时间不确定性导致内存被白白占用,引起卡顿

4.考虑大批量数据到达渲染进程的用户应用体验,确定用户交互属于高优先级任务,其他的哪些是低优先级-但必须执行的任务,哪些是中优先级任务,这里说的任务,都是渲染任务。

今天在学习一篇小册,里面有一句话引起了我的共鸣,在计算机的世界,如果有解决不了的问题,那就加一个中间层,如果还不行,那就加两个。 -后面这句是我加的

这个是我自己编写的Reactmini-react源码地址

PReact源码中,是将需要更新的组件放入队列中,然后一次清空,伪代码:

   if (setStateQueue.length === 0) {
    //清空队列的办法是异步执行 
    defer(flush);
  }
     setStateQueue.push({
    stateChange,
    component
  });

    function defer(fn) {
      //requestIdleCallback的兼容性不好,对于用户交互频繁多次合并更新来说,requestAnimation更有及时性高优先级,requestIdleCallback则适合处理可以延迟渲染的任务~
      //   if (window.requestIdleCallback) {
      //     console.log('requestIdleCallback');
      //     return requestIdleCallback(fn);
      //   }
      //高优先级任务
      return requestAnimationFrame(fn);
    }


  while ((component = renderQueue.shift())) {
    renderComponent(component);
  }


上面这段代码其实很重要,核心思想就是:

每当进入这个函数,如果发现队列队列里没有任务就去执行defer函数

defer函数执行是异步,此时defer下面的setStateQueue已经被push了进去数据,这样达到一帧完成一次渲染任务调度

当然上面仅仅一个小的任务调度,这个必须要了解,才能往下看

requestAnimationFramerequestIdleCallback使用:

clipboard.png

clipboard.png

你需要深入了解React框架的Fiber架构,这块尤其重要,是性能优化,任务调度的基础,上面有提到,React在每次diff对比阶段,将任务分割成若干个小任务,此时如果有RAFRID的任务,就要考虑去执行了

RAF的任务会每次在下一次小任务前执行

RID的任务只有在下一次小人物前,有空余时间才会执行,所以它不一定会执行。(特别高频必须执行的任务)

Fiber架构配合单个任务分割已经介绍完毕,下面出思维导图出整体的任务调度


整体渲染任务调度

clipboard.png

核心的两点:

1.释放主线程的占用,让用户的操作最快得到响应

2.合理调度任务,分高、中、低三种优先级别任务

理清思路:

1.数据通过IPC通信到达渲染进程

2.全部交给子线程去进行计算,组装数据,通过异步的postMessage事件通信,拿到渲染数据

3.调度渲染任务,用户操作交互

4.释放主线程

这里特别提示,为什么我一直强调不要使用定时器,一旦应用变得很复杂,如果任务调度不合理,定时器里的代码是要很久很久才能执行的。当然,只有重型应用会这样

渲染任务调度这块,主要是微任务,RAF,RID分片渲染以及同步代码,队列调度等手段。

主进程,接入层任务调度

clipboard.png

核心思想跟渲染进程大概一致:

1.尽量释放主进程,保持空闲,让用户的操作即时得到反馈,因为很多操作会调用主进程的接口

2.异步调度任务,写入数据库异步,解密计算可以使用nextTick等方式去调度添加队列

这里提到,任务调度的核心一点就是,频繁触发的任务必须加入队列,异步清空,否则像解密这种同步计算耗时,一旦被频繁触发就会引起阻塞。即使交给了其他进程,也要做队列

整体架构以及技术选型注意点

clipboard.png

1.技术选型时,尽量选择自己熟悉它原理的库,以及能用Demo测试模拟场景的技术,测试通过再选用,不同技术之间解决问题出发点不一样,可能会有冲突

2.队列和多进程、多线程的开启,并不是一定需要的,你可以自己设定一套规则,当一段时间的任务到达多少次被触发时候选择开启多线程,多进程。否则就是浪费

3.重型应用架构远不止这些,所以标题是浅谈,等下个月技术作者再度飞速提升一波,再来谈这些。

这里推荐关注作者的微信公众号:前端巅峰

发送加群,我会将你拉进segmentFault的前端交流群,很多小姐姐哦~

技术氛围杠杠滴~ 关键漂亮的sf小姐姐也在里面哦~

如果觉得写的不错,一定要点个赞再走,一定哦~

查看原文

小皮筋 赞了回答 · 2019-07-11

解决CSS3动画和js动画各有什么优劣

根据Google Developer,Chromium项目里,渲染线程分为main thread和compositor thread。
如果CSS动画只是改变transformsopacity,这时整个CSS动画得以在compositor thread完成(而JS动画则会在main thread执行,然后触发compositor进行下一步操作)
在JS执行一些昂贵的任务时,main thread繁忙,CSS动画由于使用了compositor thread可以保持流畅,可参考adobe的博客

在主线程中,维护了一棵Layer树(LayerTreeHost),管理了TiledLayer,在compositor thread,维护了同样一颗LayerTreeHostImpl,管理了LayerImpl,这两棵树的内容是拷贝关系。因此可以彼此不干扰,当Javascript在main thread操作LayerTreeHost的同时,compositor thread可以用LayerTreeHostImpl做渲染。当Javascript繁忙导致主线程卡住时,合成到屏幕的过程也是流畅的。
为了实现防假死,鼠标键盘消息会被首先分发到compositor thread,然后再到main thread。这样,当main thread繁忙时,compositor thread还是能够响应一部分消息,例如,鼠标滚动时,加入main thread繁忙,compositor thread也会处理滚动消息,滚动已经被提交的页面部分(未被提交的部分将被刷白)。

CSS动画比JS流畅的前提:

  • 在Chromium基础上的浏览器中
  • JS在执行一些昂贵的任务
  • 同时CSS动画不触发layout或paint
    在CSS动画或JS动画触发了paint或layout时,需要main thread进行Layer树的重计算,这时CSS动画或JS动画都会阻塞后续操作。

参考CSS Triggers,只有如下属性的修改才符合“仅触发Composite,不触发layout或paint”:

  • backface-visibility
  • opacity
  • perspective
  • perspective-origin
  • transfrom

所以只有用上了3D加速或修改opacity时,才有机会用得上CSS动画的这一优势。

因此,在大部分应用场景下,效率角度更值得关注的还是下列问题。

  • 是否导致layout
  • repaint的面积
  • 是否是有高消耗的属性(css shadow等)
  • 是否启用硬件加速

那么Chromium以外的其他浏览器呢?CSSTrick里比较了一次效率

Animated propertiesJS-based Animation更快CSS-based Animation更快
top, left, width, heightWindows Surface RT, iPhone 5s (iOS7), iPad 3 (iOS 6), iPad 3 (iOS7), Samsung Galaxy Tab 2, Chrome, Firefox, Safari, Opera, Kindle Fire HD, IE11(none)
translate, scaleWindows Surface RT, iPhone 5s (iOS7), iPad 3 (iOS7), Samsung Galaxy Tab 2, Firefox, Opera, IE11iPad 3 (iOS6), Safari, Chrome

可以看到,Chromium以外的其他浏览器没有这方面的CSS动画效率的优化。尽管MSDN提到“它可提供更好的呈现性能”,但测试并没有支持这一点。


现今CSS动画和JS动画主要的不同点是

  • 功能涵盖面,JS比CSS3大

    • 定义动画过程的@keyframes不支持递归定义,如果有多种类似的动画过程,需要调节多个参数来生成的话,将会有很大的冗余(比如jQuery Mobile的动画方案),而JS则天然可以以一套函数实现多个不同的动画过程
    • 时间尺度上,@keyframes的动画粒度粗,而JS的动画粒度控制可以很细
    • CSS3动画里被支持的时间函数非常少,不够灵活
    • 以现有的接口,CSS3动画无法做到支持两个以上的状态转化
  • 实现/重构难度不一,CSS3比JS更简单,性能调优方向固定
  • 对于帧速表现不好的低版本浏览器,CSS3可以做到自然降级,而JS则需要撰写额外代码
  • CSS动画有天然事件支持(TransitionEndAnimationEnd,但是它们都需要针对浏览器加前缀),JS则需要自己写事件
  • CSS3有兼容性问题,而JS大多时候没有兼容性问题

关注 19 回答 3

小皮筋 赞了回答 · 2019-05-19

react如何在返回的时候不重新拉取数据

react-router没有类似vue-router中的keep-alive功能,每次切换都会把之前的组件unmount掉。
自己有两个思路。
一. 数据不交由各自模块的初始化中处理(不放在componentDidMount里),交由router和各自模块的自定义触发行为处理。页面数据都放到redux里,切换route时,只有在模块对应的数据未初始化的时候,才触发对应模块的数据初始化。
二. 不依赖react-router,自己实现各自模块的加载,利用display切换当前显示的模块。

关注 2 回答 1

小皮筋 提出了问题 · 2019-05-18

react如何在返回的时候不重新拉取数据

具体要求是这样:用react做的webapp。首页有横向导航栏,点击切换路由参数,根据路由参数重新拉取数据。列表页,点击能够进入详情页。
因为在列表页已经实现了下拉刷新功能,我希望除了第一次进入每个页面通过Ajax拉取数据,后面导航之前切换,返回都不重新拉取除非手动下拉刷新。
目前想到的只是在全局为每个路由页面维护一份数据,或者根据一个变量判定是否需要重新拉取。想知道在实际开发中有这样的场景吗,是怎么解决的。

关注 2 回答 1

小皮筋 回答了问题 · 2019-05-09

解决树形数据结构的实现

我之前写过这个类似的题目,这个只要找到父子关系即可。一个参考的解答,可能有更好的做法?

function Node (label, children=[]) {
    this.label = label;
    this.children = children;
}

function getTree (data) {
    let nodes = {}, edges = {}, root;
    data.forEach(function(line, index) {
        let labels = line.split('/').filter(val=>val!=='');
        //找到根结点
        root = labels[0]
        for(let i = 0; i < labels.length; i++) {
            //找到所有节点
            nodes[labels[i]] = new Node(labels[i])
            //找到所有父子关系
            if(i < labels.length - 1) {
                edges[labels[i]]
                ? edges[labels[i]].add(labels[i+1])
                : edges[labels[i]] = new Set([labels[i+1]])
            }
        }
    })
    for(let key in edges) {
        edges[key].forEach( function(element, index) {
            nodes[key].children.push(nodes[element])
        });
    }
    return nodes[root]
}

关注 6 回答 2

小皮筋 回答了问题 · 2019-05-06

ubuntu 密码问题

连接应该是ssh -X username@ip命令吧

关注 2 回答 1

小皮筋 收藏了文章 · 2019-04-28

2019React开发者必备的技能清单

一份react开发者必备的技能清单,请查收。
入门、查漏补缺、深入学习...

image

【使用】

快速上手React,并了解其中的概念。

React文章精读,问题解答。

【API】

全面浏览API

【状态管理】

大型项目必备

Redux

Mobx

【原理分析】

深入理解

【多端应用】

移动端

桌面端

【样式】

CSS预处理

UI库

【国际化】

【工具库】

【网络请求】

Rest

GraphQL

【性能优化】

【工程管理】

代码检测

构建

持续集成

【服务端渲染】

bVboR1i?w=476&h=222

查看原文

小皮筋 回答了问题 · 2019-04-24

react-router-config renderRoutes(routes)如何做动态路由?

可以在渲染前进行一个同步的网络请求,获取到数据不就可以传入。你的意思是这个吗

关注 2 回答 1

小皮筋 回答了问题 · 2019-04-24

解决python scrapy爬虫回调函数请教。

不要同时请求,你可以先请求url1然后,然后再请求url2,在请求的时候将url1的结果传入meta,后面就可以合并

关注 2 回答 2

认证与成就

  • 获得 3 次点赞
  • 获得 5 枚徽章 获得 0 枚金徽章, 获得 1 枚银徽章, 获得 4 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2018-09-11
个人主页被 72 人浏览