设为首页收藏本站

   找回密码  加入我们
查看: 1002|回复: 108

[幻想天空] 【每日百字挑战】未来になれなかったあの夜に [复制链接]

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-2-4 23:09:28 |显示全部楼层
分享到:
本帖最后由 冰夕煜 于 2020-2-4 23:11 编辑

标题名是歌名,amazarashi的《未来になれなかったあの夜に》
所有没能成为未来的夜晚:https://www.bilibili.com/video/av76325490?from=search&seid=12717966906465099581

这首歌带给我太多力量,也是我前行的动力



作为一个程序员,这个每日挑战打算当做我个人的代码技术博客来写,肯定和大家的画风严重严重不同(笑
之前也会写技术博客,还做了个小个人网站,但经常工作需求多起来就没坚持写,也没坚持每天都学新的东西

以此贴也督促我每天都学习新的东西,唯一要求:所有文字必须是自己理解知识后自己写出来的。这也是我对于技术博客的理解,除了分享技术,更多的是借此保证自己对于技术知识点的完全理解。只有自身理解充分了,才能够写出优秀的技术博客。
也是因为长大了吧,长大了才意识到,原来自己还有那么多东西要去学,想去学

偶尔也会写写个人感受,歌曲阿电影阿生活阿成长阿其他各种学习的收获阿

加油,持之以恒,为了成为更好的自己



- 2.4

已有 1 人评分人气 收起 理由
囧I海燕 + 1 坚持不懈的鱼子酱

总评分: 人气 + 1   查看全部评分

amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-2-5 21:11:56 |显示全部楼层
本帖最后由 冰夕煜 于 2020-2-5 21:16 编辑

作为一个前端开发工程师,我本来以为md5、sha1这些玩意儿自己是不会接触的,前端要信息摘要算法干嘛使。当时选修信息安全时讲md5时就没认真听。现在想想,大学课堂上玩手机的每一分钟都是在给未来的自己挖坟。

使用md5、sha1的原因在于近期打算攻克前端上传超大型文件这一大型需求,需求就涉及到文件去重这一重点功能。试想,大量用户将大量文件上传至云服务器的oss云存储内,那么必然会出现相同文件的重复上传。若不进行去重,oss资源会出现浪费,最直接的影响就是云服务费用增长。公司的CTO(首席技术官)在技术费用上是绝对抠门的,我现在的CTO,我们叫他老赫,每个需求都会去考虑开销问题,搞的不少技术同事吐槽连连(笑

什么是md5?我之前只知道这个是个算法。啥算法,干啥使得?今天就超简单的说一下md5。

md5,在百度百科上是这么描述的: MD5信息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。

直接读这段话可能会比较难理解,没事,一句一句拆开来看。

信息摘要算法:简单来说,通过这个算法能够获得文件、字符串等信息的“唯一摘要”,可以看做是它的一个唯一id值。

密码散列函数:不用管什么是密码散列,只要知道它是一个函数就行。函数,那么就有固定的输入和输出,也就是说我们输入一个东西到md5中,它就会输出一个东西给我们。

128位(16字节)的散列值:这就是md5的输出了,不管我们给md5输入什么,字符串也好word文件也好音乐也好小毛片.avi(???)也好,他都会返回一个128位的值给我们。

md5是一个单向加密算法,它只能够从明文得到密文,无法通过密文重新得出明文。

简单来说:每个文件都能够生成一个md5值,这个值是文件的唯一标识,当文件中任何地方有变动,生成的md5值都会不同。

因此只需要计算出用户上传的每个文件的md5值并存入数据库,当后续其他用户上传文件时使用md5做对比就能够得知云存储上是否已有相同资源了。这也是为什么我们使用百度云、迅雷上传文件时在经过几秒的加载后能够显示“文件秒传”成功的原理,因为百度、迅雷已经存储了相同资源了。


md5算法的计算原理比较复杂,用最简单的两个步骤描述一下即可:

1. 对输入文件进行数据填充,填充后数据长度为 512 bit 的整数倍。
2. 进行循环的计算。每 512 bit 作为一组,前一个分组得到的 MD5 值作为下一个分组的一个输入参数,最后一个小组产出的md5值就是最终文件的md5值。

20.2.5



amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-2-6 22:59:12 |显示全部楼层
关于军功

最近在公司有一些军功上的体会,记录一下。私企不同于有关部门,能混到什么地步,更多的是看重你的个人实力,不是靠关系,也不是靠拍领导马屁。如果你有实力,很容易被上层的人发现并提拔,但如果你没有能力,即便走后门当了高层,没有能力是很容易被发现的,后果自然不必多言。

个人实力怎么提升?要怎么往上走?给自己制定合适的军功是重点。什么叫军功?在职场里军功就是你的贡献。如何找到并制定合适的军功,是和其他人区分开来的一大重点。职场有很多人,有的人每天很忙,但他做的事情都不是自己决定的。上面有什么需求、产品有什么需求,自己就去做;没什么需求就休息就学习。但可能他们的技术成长和职位成长并不是特别快,因为他们的贡献可能并不突出,日常需求考验不高的话技术成长也有限。而另外一些人,除了会做上面的部分需求,会学习,但他们更会花时间去寻找军功。他们会思考,产品当前有哪些有限待解决的问题?有哪些优化点?这些优化点的实际价值有哪些,完成后给自己带来的成长又有多少?如何下手?我想,这样的人更能够精准的提升自己,技术上、职位上全方位的提升自己。

今天主要是结合近期自己的经历,胡乱记录一下自己最近的一些思考。继续加油

20.2.6


amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-2-7 23:06:18 |显示全部楼层
本帖最后由 冰夕煜 于 2020-2-7 23:07 编辑

大文件上传:最近一直花时间准备前端大文件上传这个较大功能的实现。简单总结一下上传流程。至于大文件上传功能的解释和流程为何用这套方案,明天进行补充

1.前端选择文件后对文件进行Etag数值的计算(Etag算法:七牛云公开的获取文件 hash 值的算法:https://developer.qiniu.com/kodo/manual/1231/appendix#qiniu-etag
2.向后端传递文件Etag标识,由后端通过Etag判断文件重复情况,若重复则直接返回对应文件信息,实现“秒传”功能;若未重复则返回oss的相关签名、bucket等信息
3.前端通过阿里SDK进行OSS文件直传;阿里SDK是进行文件分片上传,能够支持文件的断点续传、进度条展示等功能,同时Oss直传不仅缩短了文件传递的步骤,通过阿里的各个地区的服务器节点还能够保证网络请求的流畅
4.前端完成文件上传后,将阿里返回的相关信息传递给后端进行相关入库操作,后端并向oss请求上传资源的信息并返回给前端

20.2.7


amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-2-8 23:58:26 来自手机 |显示全部楼层
mvp策论,英文是Minimum Viable Product,指最小可行性方案。是一种产品经理提出的策略。属于精益创业的一个知识。

如何理解mvp?简单来说,mvp就是“步子别迈太大”。有意思吧?我们以双子星举个例子吧。如果我们是口袋双子星的开发人员,我们一开始在设计整个产品时就能将现在整个双子设计出来吗?

或许可以,但这很难。现在的双子有很多功能,主页,论坛,图鉴,养成,多个系统混合。论坛里的管理也很复杂,多个板块的设计和管理。如果我们从零开始,一开始就要搞这么一个大论坛,开发周期必然很长,思考和准备过程也会耗费巨大精力。

mvp思想就是为了避免这个问题。它叫做最小可行性方案,也就是说在产品的设计上我们最开始只需要关注并产出最核心的功能即可,其他的功能之后再依次迭代添加。

比如,最初我们只需要搭建一个小discuz!论坛系统,开启一个核心板块(比如游戏讨论),那么产品就完成了。pm迷们已经有了一个可以讨论的小天地了。论坛的最重要的目的达成了。时间精力上的耗费也不多。

之后再逐渐扩大规模,比如增加板块,增加图鉴,增加养成。一步一个脚印,每次迭代会让用户更满足,而他们最需要的功能一开始就有了。

如果不这么做,用户可能要等好几个月甚至一年才能用上双子星,这是很难受的。

mvp最近在我的工作中起到的用处很大,今天突然就想用自己的话简单介绍一下,之后也会总结一下工作中用到mvp思想的例子。


20.2.8

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-2-10 01:05:27 来自手机 |显示全部楼层
微信小程序内存优化的一些思考
1.setData:
微信的setData不同于react的setState,是没有做diff的。
我想到的一个优化方案是,直接对setData进行封装,直接对全局所有setData进行一个diff,达到相同效果,直接对全局的setData都做出优化。
原理:在 setData 执行之前,让待更新的数据与原 data 数据做 diff 对比,计算出数据差异 patch 对象,判断 patch 对象是否为空,如果为空则跳过执行更新,否则再将 patch 对象执行 setData 操作,从而达到减少数据传输量和降低执行 setData 频率的目的。
具体diff算法正在研究并实现中。
2.长列表优化:
瀑布流长列表主要优化是显示区域优化,原理是使用曝光监听实现将超出屏幕一定部分的列表内的组件进行骨架屏展示的处理。减少总节点数量和渲染内容。

20.2.9
十一点开始学习,然后学完了发现忘了更新这里了 °° 应该还来得及!

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-2-11 11:01:20 |显示全部楼层
ps:完了 两天没更新 今天又重新结算了(昨天都写好了忘了发了233)
不过应该还来得及 25号之后开始结算 以后尽量每天早上开始写!

正文:

2.10煜君のreact大型总结,一ki马斯!

今天开始,重新从零开始学习react。
为啥突然又从零开始,因为明天开始煜子要带新人了(老了呀不仅是社会人,自己还是社会前辈了),自省后发现自己的react基础着实太差了。如果原理都讲不清楚,这咋好意思带新人。

之后每一天会简单总结当天的react知识点。

react,当前国内大多数公司都在作为主流框架的前端框架(其他的还有vue、angular),为什么这么多人使用react?因为react有三大优点:生态强大(成熟的解决方案多,甚至能够支持开发app、小程序、vr),上手简单,社区强大。

react一共分为三大体系。
1.react.js 用于web开发和组件的编写
2.ReactNative,用于移动端开发,即手机app
3.ReactVR,用于虚拟现实技术的开发。

当然,在学习和使用的过程中,ReactNative和ReactVR还是需要基于React.js的基础上才能掌握。我的这次大型总结也是基于react.js的学习,比较煜子的职位是前端开发工程师嘛。



React和Vue:
React和Vue是国内使用人数最多的两个框架,那么在开发一个前端项目上,如何抉择使用哪一个框架进行开发呢?我也不知道。
……这个说法有点坑(扶额),但我没实际使用过vue,对于react的掌握也不够深,因此如果简单的下判断,那太不负责任了。这就当是煜子给自己的一个提问吧。日后若有时间和精力或是业务需求,接触了vue,再回过头来进行总结。
但事实上,就我目前对于react的了解,无论是大型项目、小型项目,使用react进行开发绝不会存在坑点。所以如果只会react,放心大胆地使用吧!

19.2.10 补档
amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-2-11 20:46:03 |显示全部楼层
JSX:
使用过react,那肯定知道JSX这个东西,全称为JavaScript XML。但JSX到底是个什么东西呢?我自己想了很久都不知道怎么描述,只大概知道这是个啥。还是基础掌握不够深。
引用网上一位兄弟的描述:JSX就是Javascript和XML结合的一种格式。React发明了JSX,利用HTML语法来创建虚拟DOM。
比如这样使用:let jsxTest = <h1>hello</h1>;
这里我们可以看到,我们给jsxTest赋值了一个html中的h1节点。这就是jsx的作用。
jsx本质上是一种语法糖,当react监听到jsx的使用后,会将jsx语句解析,事实上jsxTest这个变量我们并没有给他赋值一个实际的节点,而是一个对象。这个对象起码有两个元素:节点类型元素为h1,content内容元素为hello。这也就是我们常说的虚拟dom的实现。
最后在react编译时,这个虚拟dom就会被渲染为真实dom并在页面上展示出来。
关于react对于jsx的详细编译过程我在之前的博客中有写到,这里贴一下:http://www.edison-kun.top/blog/index.php/archives/151/

20.2.11


amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-2-12 20:38:22 |显示全部楼层
JSX补充:
昨天的JSX再补充一点,JSX在解析时,当遇见了<>包裹的内容就会将其当做html来解析,当遇见了{}时就会将包裹的内容当做JavaScript来及诶

React生命周期:
react生命周期是最基础需要掌握的东西之一,而我常常把这个和小程序的生命周期搞混……特来重补基础。

什么是生命周期函数?生命周期函数其实就是指,在react组件中的某一个时刻会自动调用执行的函数。

比如render()函数,就是一个生命周期函数,它在state发生改变时自动执行(注意:不是调用setState时执行,因为setState并不一定会导致state发生改变)。这就是一个标准的自动执行函数。

另外constructor()不算生命周期函数。它属于ES6的语法,是构造函数。

React组件的四个大阶段:
react组件在从创建到销毁的过程中,我们一共可以将其分为四个大阶段:
Initialization:初始化阶段。
初始化定义属性props和状态state

Mounting: 挂载阶段。
挂载阶段,即整个组件初始化后挂载到页面的阶段,它里边有三个小的生命周期函数,分别是:
componentWillMount : 在组件即将被挂载到页面的时刻执行。
render : 页面state或props发生变化时执行。
componentDidMount : 组件挂载完成时被执行。
需要注意:componentWillMount和componentDidMount在组件的整个生命过程中只会执行一次,render函数则不仅在Mounting阶段会执行,在UPdating阶段也会执行,它的触发逻辑是state和props改变的时候。

Updation: 更新阶段。
Unmounting: 销毁阶段。
后两个阶段明日接续。

20.2.12


amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-2-13 23:44:19 |显示全部楼层
继续react生命周期:

Updation阶段,也就是组件发生改变的更新阶段。更新由两种情况来触发,一个是state改变,另外一个是props改变。

先说一下,当state改变的时候 会触发哪些生命周期函数(以下按照先后顺序执行):

1. shouldComponentUpdate。这个生命周期函数在组件即将更新之前会执行。该函数要求必须return一个布尔值,返回true时会继续组件更新,返回false时会中断组件更新,之后的生命周期函数也不执行。也就是说这个生命周期函数可以用来确保组件在我们需要的时候以及state、props正确的时候才更新。还能够起到优化组件性能的左右。优化组件性能这一点以后再提。

2. conponentWillUpdate。在组件更新(render)之前,但shouldComponenUpdate之后被执行。但是如果shouldComponentUpdate返回false,这个函数就不会被执行了。

3. render。渲染函数。此函数自然不用讲,react核心。

4. componentDidUpdate。在组件更新完成之后执行。

接下来是当props改变的时候:

1. componentWillReceiveProps。该生命周期并不是一定执行的,它有以下几个重点:
    a. 需要是子组件。因为只有子组件才会接受父级传来的props;
    b. 组件第一次存在于dom中时不会执行。只有已经完成初次渲染了,dom中已经有该组件了之后才会执行。

2. 之后的步骤同state发生变化。

20.2.13


amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-2-14 19:37:44 |显示全部楼层
继续react生命周期:

最后一个阶段Unmounting,即组件的销毁阶段。
这个阶段只有一个生命周期函数:componentWillUnmount。这个函数在组件从页面中删除的时候执行。

如何利用生命周期函数来改善程序的性能:
之前有提到过,shouldComponentUpdate能工用来改善程序的性能。

实际开发中可能不能直接发现,但当开启reaftDeveloperTools调试工具时,可以通过这个调试工具发现,有的时候state数据更新了,但是其他数据没有变动的组件也重新渲染了。这就会导致性能损耗,当组件数量越多,影响就会越大,比如会出现明显的卡顿情况。

因此需要使用shouldComponentUpdate来进行优化。之前已经介绍过,该函数的返回值能够决定组件是否继续本次更新,那么可以在这一步中控制组件的渲染。

因此给出一个通用的做法,在该函数中返回一个 nextProps.content !== this.props.content 即可。这行语句很简单,首先shouldComponentUpdate有两个参数分别为nextProps和nextState,即更新 时的props和state,将其和当前的props进行一个对比即可,如果发生了数据改变,再进行组件更新。

20.2.14(情人节,刚下班就少写点,先去陪妹子了【)


amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-2-15 22:40:04 |显示全部楼层
React暂停一天,今天先把这两天学习的另一个知识点总结一下

video标签和视频播放的深入学习


我自己对于流媒体播放、直播、点播功能非常感兴趣,这是自己以前未了解的领域。工作上过两个月也会将重心放在播放器优化上,为了提前打好铺垫,因此本周在工作时抽时间对流媒体播放的相关知识点进行了学习。

要了解流媒体,那么首先需要弄懂的一点就是MES。何为MES?全称为 Media Source Extensions,即媒体源扩展。提供了实现无插件且基于 Web 的流媒体的功能。

为何需要MSE?因为在HTML5普及之后,web端开始使用video和audio标签进行视频的播放。但是前端对于video的操作只能够限制于video标签本身提供的功能,无法对视频流进行任何操作。

以我们熟知的各大视频网站为例,成熟的视频网站播放器必然有一个切换清晰度的功能。如果我们只使用video标签来开发,要实现视频清晰度切换,那么就会通过使用js修改video的src属性。但由于video的加载不受js控制,那么直接切换src必然会导致视频播放中断、重新请求视频数据导致无法做出平滑切换的效果等问题。或者通过多个video结合z-index来实现,但这样会导致cdn流量浪费,切换也需要暂停进行控制。

而MSE提供了JS直接操作视频流的可能,因此平缓切换清晰度可以通过MSE来完美实现。
再举个例子,MSE还为前端实现动态加载mp4视频提供了实现的路径,而非一定要使用m3u8等格式。

在MSE中,允许通过JavaScript为HTMLMediaElement(及audio和video标签)动态构造媒体源。什么叫动态构造数据源呢?
之前直接使用video标签时,我们直接给src传入视频地址作为数据源,也就是说数据源是固定的一整个媒体对象。
但使用MSE后就不是这样使用了,我们可以将src值替换为引用一个MediaSource对象。通过URL.createObjectURL方法来实现生成对MediaSource对象的引用。

MediaSource对象是什么?简单来说,它是一个包含即将播放的媒体文件的准备状态等信息的容器,相当于一份可用于播放的media data。MediaSource中包含了一个或多个SourceBuffer对象。SourceBuffer对象可以理解为具体的音视频轨道,或也可以简单理解为一块可以单独用于播放的数据,它可以解码为音频、视频或文本数据,并由video处理进行播放。当MediaSource中包含可用的SourceBuffer时,MediaSource就可以用于video播放了。

重点来了:通过JavaScript,我们可以向SourceBuffer对象动态添加数据片段。这样,我们可以自己来实现实现拉取mp4的部分数据后,将其动态放入SourceBuffer,从而控制video的加载进度。而非直接通过video标签拉取整个mp4文件。除了控制拉取进度,还可以根据系统性能及其他因素自适应调整所添加媒体数据的数据质量(比如清晰度)。

具体mp4视频的播放流程如下:
1. 请求 mp4 视频数据:可以结合视频 Range 服务,做到精确加载部分数据。
2. 将加载数据生成MediaSource
3. 使用 video 进行解码完成播放 image2020-2-15_3-17-50.png

具体流程可以见上,图片虚线内的是重复的过程,从而做到动态控制加载。可以看到事实上过程更加复杂,range服务应该是指http的range请求头(这点还要研究);第二步实际上还包括了编写解析器将加载回来的部分 mp4 视频数据进行解复用和将解复用的视频数据转成 fmp4 格式的过程,然后才传递给 MediaSource,这一点也是之后的研究内容。


MDN上的详细介绍:https://developer.mozilla.org/zh-CN/docs/Web/API/Media_Source_Extensions_API  。业内对于MSE的使用也很多,比如头条的西瓜播放器:https://h5player.bytedance.com/ ,原理也是通过MSE来进行。
amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-2-16 21:36:12 |显示全部楼层
React中父子组件间的传值和单项数据流:

父组件向子组件传值,是通过组件属性的方式进行传值,子组件需要使用这个值时从this.props里中取值即可 。

子组件如果要向父组件传值怎么办呢?但react明确规定,子组件无法直接操作父组件中的值。因此子组件需要借助一个父组件的方法来修改父组件的内容。因此需要在父组件中定义一个修改state的函数,将这个函数通过组件属性的方式传递给子组件,子组件在通过this.props取到该函数后调用该函数来进行父组件的内容修改。

从这我们衍生出react的一个概念:单项数据流。何为单项数据流?父组件可以直接将值传递给子组件,子组件可以直接使用这个值,但是无法对这个值直接进行修改。对子组件来说这个值是只读属性的。这种情况就属于单向数据流,只能父组件直接向子组件进行传值。

为什么要有单向数据流?举个例子,复杂类型的数据(也就是对象)更新和简单类型的数据更新是不一致的,父组件向子组件传递一个对象,子组件中对这个对象中的某个属性如果进行了修改(假如支持),那么父组件中的原本对象也会改变,导致更新——这就导致了数据的絮乱。

增加了单项数据流的概念,帮助降低了我们组件间通信的代码耦合,让组件间的通信更为清晰,不会因为上述bug导致debug难。

函数式编程:
react是函数式编程框架。那么什么是函数式编程?它又有什么好处呢?

这里我用我自己的理解来讲一下函数式编程。函数式编程就是将一切功能都封装成函数,函数和函数的相互调用构成了最终整体的功能。举个例子,我们需要对一个二叉树a进行反转,那么我们写一个专门用于二叉树反转的方法,直接调用这个方法并向其传值a即可。

当然也可以不封装,直接在代码里写对这个a的反转。但如果有一百个二叉树都需要反转,代码量就增加了一百倍。这就是命令式编程,他关注解决问题的步骤。但如果用一个封装的函数,那么代码量明显大大减少。可以理解,函数式编程更关心数据的映射,我们传递一个二叉树进去,它返回一个对应的反转回来。

函数式编程有什么好处?明显的好处有两个:

1. 函数式编程让我们的代码更清晰,每个功能都是一个函数。复用更加方便,代码量也大大减少。
2. 函数式编程为我们的代码测试代理了极大的方便,更容易实现前端自动化测试。我们只需要关心各个函数编写是否正确即可。传进一个值,返回我们期望的值。那么测试就ok了。

20.2.16


amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-2-17 23:21:54 |显示全部楼层
Props数值的校验
在从父组件向子组件传值时,可以意识到我们对于所传的值是非常自由的,想传多少传多少,想传什么传什么。而平时煜子进行react开发时就是这样的,一点危机意识都没有,这就是我现在不能成为大佬的原因吧(扶额
一个成熟的工程师,进行开发时一定不能偷懒,起码在思考上面不能偷懒。现在埋的每一个坑,都是以后线上爆炸的可能因素。一定不爆炸可能我们无法做到,但在爆炸后能够立刻找到问题根源却是我们应该做到的。以这个传值为例,如果我们对每个值的类型做了硬性规定,那么在debug时不就可以排除该因素了吗?

很明显,父组件传来的值是应该被约束的。也就是为了保障子组件内部数据的正确性和业务逻辑的稳定,应该对props里的数据进行约束。react就为我们提供了这个工具——PropTypes

PropTypes使用很简单,在最上面引入之后,直接对于子组件进行设置即可。比如子组件叫做PokemonItem,有一个id,number类型;一个name,string类型;一个skill,函数类型,那么就可以如下约束:

PokemonItem.propTypes={
    name:PropTypes.string,
    skill:PropTypes.func,
    id:PropTypes.number
}

如果该属性是必须的,那么直接在类型后面跟上.isRequired即可。如果要设置props的默认值,则使用defaultProps即可,使用方法如下:

PokemonItem.defaultProps = {
    name:'路卡利欧'
}

20.2.17



amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-2-19 22:27:38 |显示全部楼层
好气啊 昨天工作到十一点半又忘了写了 这样我何时才能拿到双子蛋蛋!
以后每天一想起这边马上过来写才是王道 绝对不能推迟!!!

_ref的使用
编写组件中的方法时,经常会出现e.target这样的代码。这种代码语义化很模糊,对代码可读性和可维护性都不好。针对这一点我们可以使用ref进行优化

举个例子,正常情况下我们编写input时如下:
<input
    onChange={this.inputChange.bind(this)}
/>

因此,inputChange方法里,要获得输入的值就得使用e.target.value来获取(e为参数)。但如果使用了ref就方便很多:

<input
    onChange={this.inputChange.bind(this)}
    ref={(input)=>{this.input=input}}
/>

加了ref这一行,input被赋值到this.input中,因此inputChange方法里如果要获得对应值,直接调用this.input.value即可。可读性大大提升。
当然ref说是这么说,能够提升语义化。但在煜子的实际工作中基本不怎么使用这个东西。首先e.target这个方法其实所有程序员都很熟悉了,我认为没有必要进一步去优化它;其次新增一个this.xxx,可读性就更好了吗?如果有多个input那要有多个this.inputxxx。也不见得特别方便。不过ref这个东西是要知道是干什么的,否则阅读相关源码看到这个可能会懵逼。

20.2.18



amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-2-19 22:29:22 |显示全部楼层
Redux:

使用react的开发肯定都听说过redux。redux究竟是啥,有什么用?今天主要对redux的意义进行一个总结。

上面有总结过,使用react时,如果需要进行组件间的通信,那么必然是父子组件的通信。且不提父子通信的复杂程度(虽然也不是特别复杂),如果我们要实现“爷孙”辈组件的通信呢?如果要实现“兄弟”辈组件的通信呢?可能也还好,只是需要一个父组件作为沟通桥梁。那么更复杂一点,一个组件要和它父组件的父组件的另一个子组件的子组件的子组件通信呢?那岂不是要加更多的通信桥梁?想一想就晕了 。

redux就是为了解决这个问题而诞生的。官方介绍称,redux是一个管理react的数据状态和ui状态的JavaScript工具。

redux是如何做到这一点的?其实很简单,之前的组件通信是一层一层进行传递。redux中,redux将状态存储在一个单独的store仓库中,当组件需要时可以从store取到当前状态,也可以去修改store中的某个状态。而当store中某个状态被改变时,其他依赖该状态的组件也会自动更新。

关于Flux:
flux也是一个状态管理工具。但可以这么说,redux是flux的升级版本。所以如果掌握了redux,就可以不用再学习flux了。
接下来几天会每日学习redux。redux我还是用了非常久的,是非常方便的工具。但由于基础掌握不够,对redux不够精通,最近对于redux的使用上有一些误区,自己也陷入了疑惑。因此重新从基础学一遍redux,帮助自己解决疑惑。

20.2.19


amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-2-20 02:44:03 |显示全部楼层
redux的工作流程:

先简单描述一下redux的流程,这个流程其实刚学的时候非常不好理解。现在会用redux了,但是让我从头把它讲出来,我还是感到不好讲。

redux主要有四大部分:Action Creator,store,Reducer,component

最简单的一句话,组件如果要获取状态,是从store中获取。组件如果要修改store中的状态,那么需要通过ActionCreator创建一个action,reducer通过action来修改store中的状态。

这么理解其实很难,网上最常见的理解方法是用人去图书馆借书的例子来讲解redux的工作流程。但煜子一直觉得这个方法很坑呐,不适合我。每次这种复杂的知识逻辑我的理解方式是:硬啃。硬啃+上手操作后用自己的概念去理解。

因此用我的理解来叙述一下:
首先,组件a有状态要传递给组件b,那么a需要把状态存入(或者是修改)store中。如何去存呢,a需要调用ActionCreator创建一个action,表达我现在要修改状态了。action可以看做一个纸条,传递这个信息。而处理器就是reducer,store只能通过reducer来修改。reducer收到action后,进行store的相关修改。因此状态成功存入store中。当组件b需要这个状态时,直接从store中获取(怎么获取之后再讲)。

知识就是这样,你不能生搬硬套别人的理解,要自己去形成一套自己的理解。自己真正理解了,这个知识点你才掌握了。

20.2.20


amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-2-21 01:41:05 |显示全部楼层
今天总结一下redux里store和ruducer的初始方法。这一套流程我已经完全不记得了,问题很严峻啊。

具体react和redux的下载和引入方法就不提了,npm很简单。

在react项目中引入redux后。首先要创建store。昨天的总结里很明显可以知道,store作为状态储存仓库是redux的核心。

核心代码很简单,在项目的store文件夹里新建index.js文件,写入如下语句:

  1. import { createStore } from 'redux'  // 引入createStore方法
  2. const store = createStore()          // 创建数据存储仓库
  3. export default store                 //暴露出去
复制代码


完成store的创建后,接下来就是store的管理者reducer了。新建reducer.js文件,写入如下代码:

  1. const defaultState = {}  //默认数据
  2. export default (state = defaultState, action) => {  //就是一个方法函数
  3.     return state // 这里写的很简单,就是不管什么action,均返回默认状态数据
  4. }
复制代码


完成reducer后,如何将reducer和store添加“管理”关系呢?在store/index.js文件里稍作修改即可:

  1. import { createStore } from 'redux'  //  引入createStore方法
  2. import reducer from './reducer'   
  3. const store = createStore(reducer) // 创建数据存储仓库
  4. export default store   //暴露出去
复制代码


组件中如果要使用store中的方法,直接在组件中引入store即可

  1. import store from './store'
复制代码


然后通过store.getState()就可以拿到store中的所有数据了。
  1. store.getState()
复制代码


当然,通常开发是不会直接调用getState的,通常会使用一个叫mapStateToProps的方法。这个之后再学习。为什么要有 mapStateToProps?另外还有一个mapDispatchToProps是什么有什么意义?这是之后煜子的学习重点。现在对于这些,我还是处于会用但不懂为什么这么用的概览。

问题果然很严峻呐。

20.2.21



amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-2-24 20:25:57 |显示全部楼层
周末睡了两天 彻底忘了
又要从零开始  唉 坚持坚持 今天先补充周末两个总结

上周有一次是针对MSE媒体源扩展进行了学习,先针对MSE媒体源做一些知识点补充
当前video标签直接使用会导致的流量浪费情况:
1.video标签在进行视频播放时,如上周总结所说,video标签对视频的加载是不受js控制的。根据preload字段它会自动加载所有数据或是只加载meta元数据,这一点在很多视频网站上就可以发现。当只播放了几秒钟视频时,进度条内的灰色已加载内容通常已经显示很多了。如果用户此时退出播放,那么这一块数据流量明显就属于浪费了 ;
2.同样原因,如果用户不断的进行seek(进度条拖拽)也会造成较多的流量浪费。头条曾经做过统计,在短视频领域,用户seek的频率在 80%,所以这部分流量浪费情况也是相当大的。
如何做到通过MSE进行视频播放流量节省的效果:
1.设置每次加载的数据包大小
2.设置预加载时长,比如10秒。
3.开启加载队列,完成第一次数据包下载,判断缓冲时间和预加载时长是否满足,如果当前视频已缓冲内容播放时长小于规定的预加载时长,则请求下一个数据包。



20.2.22


amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-2-24 20:57:21 |显示全部楼层
流媒体播放协议

煜子现在工作中主要是进行小程序开发。目前小程序目测是不支持MSE的(但MSE已经非常成熟了。当前业内成熟的框架很多,比如头条的西瓜播放器),要实现流媒体播放还是得依靠m3u8。即HLS协议:
HLS全称为HTTP Live Streaming,苹果公司开发的基于HTTP协议的流媒体解决方案。基本原理是将视频文件切分成小片(即ts文件,实际的播放内容,每一片都可以单独播放)并建立索引文件(即m3u8文件)。
另外需要知道,HTML5里的video标签是不直接支持HLS的(移动端浏览器好像大部分都支持,但PC端只有苹果的Safari支持),需要自己封装或者是采用成熟的播放器插件进行播放。封装基本原理基本是:加载m3u8文件并进行解析,获取m3u8索引文件内的相关信息,从而获取到实际要播放的媒体资源信息(即ts文件)。随后就是利用MSE进行动态加载,具体流程同上面的“通过MSE进行视频播放流量节省流程”。

小程序端的video组件直接支持HLS协议,因此可以直接播放m3u8文件。
另外流媒体解决方案并不止一种,除了HLS,最为出名的是DASH,bilibili就是使用的这个。DASH是一套新的国际标准(主要原因还是HLS在其他浏览器上的支持问题),不过基本原理和HLS类似。具体详细区别之后有空了再研究(因为小程序现在不支持DASH&#128514;虽然DASH的未来好像更美好一些,毕竟是朝着通用标准去发展的)。在研究两个协议的区别时发现还要看文献……贴一下链接:http://www.doc88.com/p-9962134662286.html

20.2.24


amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-2-24 22:45:51 |显示全部楼层
上面那个最后日期写错了 应该是23号的


今天继续redux

我们先创建一下action:
举个例子,我们在代码中有一个input,input的onChange绑定如下事件:
changeInputValue(e){
    const action ={
        type:'changeInput',
        value:e.target.value
    }
    store.dispatch(action)
}

action就是一个对象,这个对象一般有两个属性,第一个是对Action的描述,第二个是要改变的值(也可以是多个)。
action创建完后要通过store的dispatch方法来传递给store。

接下来写一下reducer的相关逻辑
之前有学习过,store只是一个仓库,它并没有管理能力,它会把接收到的action自动转发给Reducer让reducer去处理。

因此我们看一下reducer里的函数参数:state和action。state指的是原始仓库里的状态,action指的是action中新传递过来的状态。因此有了这两个值,就可以来修改store中的状态了。
首先根据type类型进行判断,可能有多种类型的type,针对需要的type进行选择。我们需要重新声明一个变量newState。(记住:Reducer里只能接收state,不能直接改变state。),所以我们声明了一个新变量,然后再次用return返回回去。返回去后store就会根据值来修改其中的数据。

20.2.24


amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-2-25 10:07:14 |显示全部楼层
总结一下redux中的几个重点:

1. store必须是唯一的。
createStore()创建了store,但这个只能够调用一次用于创建store。之所以只有一个store,我的理解是并不需要使用多个store来管理多份数据,在一个store进行拆分就可以了。而且store还会链接如各种中间件的东西,管理多个store会非常复杂。

2. 只有store能改变store中的数据
在使用过reducer后,很容易误理解是reducer来改变store中的数据的。但事实上并非如此。store中的数据是严禁其他地方进行修改的 ,只能够store自己修改。Reudcer只是返回了更改的数据,但是并没有更改store中的数据,store拿到了Reducer的数据,自己对自己进行了更新。

3. Reducer必须是纯函数
纯函数定义:如果函数的调用参数相同,则永远返回相同的结果。它不依赖于程序执行期间函数外部任何状态或数据的变化,必须只依赖于其输入参数。其实可以简单的理解为返回的结果是由传入的值决定的,而不是其它的东西决定的。比如调用ajax请求服务器返回数据;或者返回值依赖当前时间、当前日期、使用者等,这些如果使用就不属于纯函数。

20.2.25


amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-2-26 00:34:34 |显示全部楼层
关于react中的无状态组件:
首先什么是无状态组件?无状态组件顾名思义就是没有状态的组件,如果一个组件不需要管理 state 只是纯的展示,那么就可以定义成无状态组件。无状态组件通常用于简单的UI组件,

无状态组件的数据展示不依赖本身的state,全靠父级传递过来的props来决定。使用无状态组件能够提升组件的性能。为什么能提升性能呢?

首先看一下无状态组件要怎么编写,下面是一个普通组件
  1. import React, { Component } from 'react';
  2. class TodoListUi extends Component {
  3.     render() {
  4.         return (<div>123</div>);
  5.     }
  6. }
  7. export default TodoListUi;
复制代码


改写成无状态组件就是如下:
  1. import React, { Component } from 'react';
  2. const TodoListUi = props => {
  3.     return (<div>123</div>);
  4. }
  5. export default TodoListUi;
复制代码


可以看到,无状态组件事实上就是一个返回jsx的函数。看起来是一个组件,但它完全没有组件的相关生命周期,性能比起普通组件能够大大提升。

不过这种组件主要是为了复用才单独编写,如果不复用,那直接把这个函数写在父级组件里也未尝不可。

说道无状态组件,明天针对PureComponent来进行学习。PureComponent我还真没怎么用过,它是react15.3版本推出的。

20.2.26


amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-2-27 01:16:12 |显示全部楼层
PureComponent学习

在React15.3中,新加了一个PureComponent类,顾名思义,就是纯组件的意思。

PureComponent的使用方法非常简单,声明组件时,把继承类从 Component 换成 PureComponent 即可。

PureComponent的作用就是改写了shouldComponentUpdate方法。之前已经总结过,组件的state和props的改变就会触发render,但是组件的state和props没发生改变,render就不执行。所以为了提升性能,我们会在shouldComponentUpdate方法里写一些判断是否应该渲染的逻辑去优化组件性能。

PureComponent的作用就是,只有PureComponent检测到state或者props发生变化时,PureComponent才会调用render方法,因此,不用手动写额外的检查,就可以达到提高性能的目的。

但是PureComponent只会对state和props进行浅比较,对于数组、对象的内部元素改变它无法监听到。比较深层次对比也是需要性能的。因此PureComponent并不是适用于所有组件,它更适合用于UI组件。



20.2.27


amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-2-28 18:55:06 |显示全部楼层
react的中间件

中间件这个概念我从一开始理解就不透彻,今天正好从底层彻底掌握这个知识点。

redux作者对于中间件的描述如下:“It provides a third-party extension point between dispatching an
action, and the moment it reaches the reducer.”。即这个是一个可以第三方编写的位于发送action和reducer处理action之间过程的扩展插件。在middleware中可以检阅每一个流过的action,挑选出特定类型的action进行相应操作,也能提供一次改变action的机会。

为什么需要中间件呢?举一个使用redux中一个简单的同步数据流动的场景:
点击button后,在回调中dispatch一个action,reducer收到action后,更新state并通知view重新渲染。

如果我们需要打印发送action时的相关信息,reducer处理前的store数据和处理后的数据。那么就需要修改action的代码以及reducer的代码去一一响应,每一个都要加,不具有普及性。

如果我们需要在点击button时调用接口,那么就需要先通过ajax获取信息后再将数据传给action。但如果action本身就能够支持先进行接口调用后再dispatch传递给reducer,复用性不是就更好了吗。

因此,面对多种多样的业务需求,单纯的修改dispatch或reducer的代码显然不具有普世性,我们需要的是可以组合的,自由插拔的插件机制。

因此中间件诞生了,redux中,中间件middleware的特点是为了增强dispatch而出现的。它的流程是,把dispatch过程中自由扩充针对action的处理,将最后的action发送给reducer。

如图所示:


可以看到途中有很多个中间件,每一个中间件都可以用于处理一个业务需求,通过串联多种中间件,可以实现变化性高、自由度强的项目。
最后两个问题:middleware 怎么写?redux 是如何让 middlewares 串联并跑起来的?这个明儿继续学习



20.2.28



amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-3-1 13:05:22 |显示全部楼层
刚写完发现双子维护,不过没事,这一份当昨天的。『男人,对自己狠一点』

函数柯里化


由于middleware的底层设计思想涉及到函数柯里化,因此先对柯里化做一个学习

这里我用网上看到的一个例子来举例。这是我翻阅无数篇教程后唯一一篇比较容易理解的【捂脸

假设函数库里提供这样一个拼接URL地址的函数:

  1. function simpleURL(protocol, domain, path) {
  2.     return protocol + "://" + domain + "/" + path;
  3. }
  4. simpleURL('http','www.pm222.com', 'index.html');
复制代码


这个函数一目了然,就是用于传递一个url的多个属性拼接出一个最终url来,因此最后我们得到了双子域名地址'http://www.pm222.com/index.html'
函数很简单,但是如果我是双子开发人员,使用到这个函数时通常第一个参数和第二个参数都不会变,唯一需要改变的是第三个参数。即站点中的任何页面或资源,前两个参数永远固定,只需要改变第三个参数。

显然每次传递两个同样的参数很多余,那么自然我们会改成单独参数

  1. function simpleURL(path) {
  2.     return "http://www.pm222.com/" + path;
  3. }
复制代码


这样改有两个问题
1. 如果该库函数还需要被其他人或其他地方使用,直接改库函数这条路是绝对行不通的。
2. 其次就算对函数有绝对的控制权,这样改显得也非常的不灵活,如果哪天站点要加上SSL呢?那又要进一步修改库函数

因此可以用柯里化解决:
柯里化:将函数与其参数的一个子集绑定起来后返回一个新函数。

比如用bind柯里化一下:

  1. var myURL = simpleURL.bind(null, 'http', 'www.pm222.com');
  2. myURL('myfile.js');     //http://www.pm222.com/myfile.js

  3. //站点加上SSL
  4. var mySslURL = simpleURL.bind(null, 'https', 'www.pm222.com');
  5. mySslURL('myfile.js');  //https://www.pm222.com/myfile.js
复制代码


再回过头体会一下柯里化定义:其实就是将函数与其参数的一个子集(部分参数)绑定起来后返回一个新函数。柯里化后发现函数变得更灵活,更流畅。当然,一开始也会更难理解。

不用bind来实现柯里化

  1. var currying = function(fn) {
  2.     var args = [].slice.call(arguments, 1);
  3.     //args为["https", "www.pm222.com"]
  4.     return function() {
  5.         var newArgs = args.concat([].slice.call(arguments));
  6.         // newArgs为 ["https", "www.pm222.com", "myfile.js"]
  7.         return fn.apply(null, newArgs);
  8.         // 相当于返回了simpleURL('https', 'www.pm222.com', 'myfile.js')
  9.     };
  10. };

  11. var myURL2 = currying(simpleURL, 'https', 'www.pm222.com');
  12. myURL2('myfile.js');    //http://www.pm222.com/myfile.js
复制代码


如此,根据不同的参数需要,就可以定出不同的简洁后的函数。比如上面是带ssl的简单函数一个,再调用currying(simpleURL, 'http', 'www.pm222.com')就得到了不带ssl的函数一个。

但柯里化实际的好处有哪些?除了更好的简洁函数,同时具有易修改性。还有其它的好处吗?明儿继续



20.2.29


amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-3-1 22:59:31 |显示全部楼层
今天插一下小程序的底层双线程机制,下周开始要进行内存优化

小程序教程中的描述:https://developers.weixin.qq.com ... 0b87b008612f5f5640a

数据更新时的渲染流程总结:

每当小程序视图数据需要更新时,逻辑层会调用小程序宿主环境提供的 setData 方法将数据从逻辑层传递到视图层,经过一系列渲染步骤之后完成UI视图更新。完整的通信流程如下:

1. 小程序逻辑层调用宿主环境的 setData 方法。
2. 逻辑层执行 JSON.stringify 将待传输数据转换成字符串并拼接到特定的JS脚本,并通过evaluateJavascript 执行脚本将数据传输到渲染层。
3. 渲染层接收到后, WebView JS 线程会对脚本进行编译,得到待更新数据后进入渲染队列等待 WebView 线程空闲时进行页面渲染。
4. WebView 线程开始执行渲染时,待更新数据会合并到视图层保留的原始 data 数据,并将新数据套用在WXML片段中得到新的虚拟节点树。经过新5. 虚拟节点树与当前节点树的 diff 对比,将差异部分更新到UI视图。同时,将新的节点树替换旧节点树,用于下一次重渲染。

综上,逻辑层使用 setData 向视图层传输数据,由视图层进行页面更新。从架构上,逻辑层和视图层无法直接共享数据的,数据传输是一次跨进程的通信,会有一定的通信开销,这一开销与传输的数据量正相关。

20.3.1


amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-3-2 21:36:19 |显示全部楼层
从用户事件绑定优化小程序内存

从小程序的事件通信原理上可以得知,触发用户事件时,会导致信息从视图层到逻辑层的传递。每一次事件触发都会消耗一次通信成本,那么去除不必要的事件通信自然能够起到优化作用
优化措施:去除由于多次迭代导致的无用事件绑定(绑定的事件无定义或执行逻辑无意义);其他页面后续随迭代过程进行排查。

同时这个通信过程是异步的,会产生一定的延迟,延迟时间与传输的数据量正相关。那么为了节省通信成本和减少延迟事件,应该减少传输数据量。
优化措施:事件绑定时需要传输target和currentTarget的dataset,因而不要在节点的data前缀属性中放置过大的数据。优先针对重点页面检查,其它页面后续随迭代过程进行优化。

部分用户事件会频繁触发,如PageSrcoll、Resize的事件,针对这类事件可以做以下优化:
优化措施:
1.只在必要的时候监听该类事件
2.避免在该类型事件中执行复杂逻辑
3.避免在该类型中频繁调用 setData,若需要频繁调用setData,合理使用函数防抖和函数节流进行优化
4.在某些场景下,比如曝光量统计。通常的做法是,监听 onPageSrcoll 事件,并不断查询元素位置,节点信息查询(createSelectorQuery)也是非常耗时的,会影响小程序通讯渲染的性能。在这种情况下,使用节点布局相交状态监听(IntersectionObserver)替代,减少不要的通信。(网络的解法,具体还需要验证)

20.3.2


amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-3-3 19:45:06 |显示全部楼层
从自定义组件拆分出发优化小程序内存

自定义组件除了有利于代码复用,提升开发效率外,还可以有效的提升页面局部频繁更新时的性能。自定义组件的更新只在组件内部进行,不受页面其他部分内容的影响,可以大大降低页面更新的开销。

因此除了由于逻辑复杂、依赖生命周期等情况需要选择组件进行开发外,还应该将页面中一些需要高频执行 setData 更新的功能模块(如倒计时、进度条等)封装成自定义组件嵌入到页面中。当这些自定义组件视图需要更新时,执行的是组件自己的 setData ,新旧节点树的对比计算和渲染树的更新都只限于组件内有限的节点数量,有效降低渲染时间开销。

但并不是使用自定义组件越多会越好,页面每新增一个自定义组件, Exparser 需要多管理一个组件实例,内存消耗会更大,此外多次嵌套组件也会导致节点深度剧增。当内存占用上升到一定程度,有可能导致 iOS 将部分 WKWebView 回收,安卓机体验会变得更加卡顿。

因此要合理的使用自定义组件。在代码设计上,避免无用、不合理的组件拆分。

优化措施:
1.针对复杂页面进行梳理,将没有必要拆分为组件的组件解耦,重新在父级中进行实现;
2.在进行页面相关功能开发时,开发者若发现有无需拆分为组件的,顺带进行改写;
3.新功能开发时,合理设计组件拆分,杜绝无意义组件的新增。

20.3.3


amazarashi

使用道具 举报

Lv.5 口袋中级训练员

子夜。新月。

Rank: 5Rank: 5

UID
237474
帖子
2720
精华
0
积分
480
BP
0 点
阅读权限
50
注册时间
2009-7-20

神奇宝贝信息

 神奇宝贝图鉴:122 (GT 70)
 双子宝贝图鉴:7 (GT 0)
 宝贝养成成就:17 (250 Pts)
发表于 2020-3-4 00:44:15 |显示全部楼层
从模板和组件的选择优化小程序内存

曾经有一段时间,在我负责的小程序项目中我们启用了将模板template全部改为组件实现的策略。原因在于一定程度上组件在数据管理更加方便,能够定义自身的数据,不需要所有数据处理都在page.js中进行;其次组件更符合我们的组件化设计思想,且具有自己的生命周期,功能上适用性更广;最后在代码管理上更加方便。

这个制定在当时性能问题未暴露的时候并没有带来什么关注,但随着后续复杂页面的增加,组件的嵌套深度逐渐增加;另外存在为保障可读性,即便组件不存在复用情况,也会根据功能不同而拆分组件,导致组件数量进一步增加。

我的理解上,自定义组件由于具有完整的四个文件(wxml、js、json、wxss),可以将其看成一个普通的页面;而模板只具有其中两个文件(wxml、wxss),没有js逻辑,因此可以看做是页面中的一个可复用节点。

那么两者对于性能的影响自然就可以看出来了,举一个极端的例子,两个具有相同功能的页面a和b,a页面中包含10个组件,b页面包含10个模板。那么a页面就相当于一个页面中内嵌了10个页面,而b页面则无内嵌,但整体的逻辑更加复杂,js中需要管理和处理的数据更多。相比之下,大部分情况中b页面的性能会比a页面好(其他情况见下一方案)。

当然这只是极端例子,页面b的实现肯定是不符合组件化思想的,它只实现了wxml上的组件化拆分而非js逻辑上的。在可维护性、可读性上也远远次于页面a。但是从性能上考虑,全部使用自定义组件也必然是存在问题的,逻辑简单、复用量低的组件完全可以使用模板来代替。

20.3.4


amazarashi

使用道具 举报

您需要登录后才可以回帖 登录 | 加入我们
*滑动验证:

Powered by Discuz! X2© 2001-2011 Comsenz Inc.
回顶部