Fork me on GitHub
杨溢的博客

努力向上爬的小人物


  • 首页

  • 归档

如何阅读框架源代码

发表于 2018-01-13

不管对于那个段位的 Developer 来说,读源码都是一件好处颇多的事情,特别于初学者而言,这能迅速的吸纳优秀框架精华代码营养,迅速成长。不巧的是,晦涩难懂的源码,很容易让人心生怯意。今天分享就来谈一谈读源码的方法,希望能帮到一些有心读源码的朋友

一、了解框架解决了什么问题

这不光对读源码有帮助,对整个学习都很有帮助。思考一个问题:你学习 Vue\React 的原因,除了它们如日中天,再不学习都不好意思找工作了,还掺杂了一些它们的某些优秀特性能给我带来某某好处的思考么?
新潮的框架,开发者需要而且也应该去了解,用人单位需要当然是本能的驱动力,什么火学什么也无可厚非,但是在闷声学习之前,需要加上一层思考,相比之前的技术体系,这个框架到底解决了什么问题,优势在哪,怀着目的去学习才不至于迷茫,例如 Vue\React 最大的优点是什么呢?组件化吧,带着框架是如何解决这个问题的疑问去学习,定能事半功倍
对于读源码来说,这一步就更关键了,如果都不了解代码是要干什么的,怎么会清楚它为什么这么写呢?再细分一下,在仔细阅读某个模块的文件的时候,也应当对模块的功能有个整体的把握

二、了解框架的设计思想

这一步尤为关键,我们看不懂源码(或者看起来举步维艰),并不是因为不懂某一句语法,而是不明白作者的思路。举一个简单的例子:
//这个方法可以获得point2顶角的弧度值
function getAngle(point1, point2, point3) {
var bb = (point2.y - point1.y)(point2.y - point1.y) + (point2.x - point1.x)(point2.x - point1.x);
var aa = (point3.y - point1.y)(point3.y - point1.y) + (point3.x - point1.x)(point3.x - point1.x);
var cc = (point3.y - point2.y)(point3.y - point2.y) + (point3.x - point2.x)(point3.x - point2.x);
var cosa = (bb + cc - aa)/(2Math.sqrt(bb)Math.sqrt(cc));
return Math.acos(cosa);
}
getAngle 方法接收三个坐标参数,可以计算出 point2 顶角的弧度值,如果不告诉你这使用了运用三角形的余弦定理,恐怕你看半天也看不出来这是怎么算出来的

那么我们可以通过什么渠道去了解框架的设计思想:

  • 到框架的官网看文档,开源的框架,甭管详不详细,这肯定是第一手权威资料
  • 到网上搜别人的分析总结(源码分析也不会少),大多数情况下,都会有大神已经研究过了,站在巨人的肩膀上,能省不少事

另外,设计思想是整个框架层面的,对于每一个实现细节,又会使用不少设计模式,例如函数式编程(Js 中最为常用)、单例模式、代理模式、工厂模式等等,这就需要平时的积累了。有一定代码量的积累之后,建议阅读一些设计模式类的书籍,对自己的代码设计,以及阅读别人的源码,都很有益处。

三、搭建调试环境,摸清执行主脉络

第一节我们提到,细分到每个模块,要对模块功能有个整体的把握,如何去做到这个“把握”?除了官方文档和网上查阅的资料,最好的办法就是写一个简单的 Demo,搭建好测试环境,增加一些调试信息,自然能理清除框架的生命周期中,每一步需要调用那个模块(对于目录结构很清晰的优秀框架,有时候也可以凭直觉猜测,打印日志确认)

四、分清主次

框架源码就是一颗枝繁叶茂的参天大树,而你要做的事情是从根部网上爬。树要这么多分支,时间又是这么昂贵,阅读的策略很重要。我们的阅读路径,要以主要流程为主(也就是树的主驱赶,这样才能尽可能快的到达顶点),对于一些细枝末节,再这之后再来慢慢啃(或者有必要的时候)例如,要去阅读 Vue 的源码,有个目录是解析模板,生成语法树 AST 从而最终生成 Render Function 的, 其实这一步最关键的是这个 Render Function 的生成结果,对于如何去解析模板、生成语法树,可以先放一放,回头需要的时候再回头看。否则你很容易卡死在某个点上出不来,从而产生放弃的念头

五、坚持不放弃
技术策略得当,遇到棘手过不去的问题也很正常,这个时候考验的就是毅力了,继续调试、搜索资料、或者找个大神来问一问都行,只要不放弃就好~~

Vue 组件间的样式污染

发表于 2018-01-13

一、污染是如何产生的?

得益于 Vue-loader,在 Vue 中可以使用类似于 Web Component 的组件化写法,<template></template><style></style><script></script>,在大多数情况下,我们希望组件间定义的样式是相互隔离的,在 Weex 当中的确如此,组件天生隔离,可是在 Vue 当中,运行的载体还是浏览器,所有的样式类还是会通过

// 编译后

` 每个组件有唯一的 scopeId,按理说,这样应该能够做到样式隔离了,实际上,**这种方式其实表现已经足够好了,除了以下这种情况~~** ## 三、ScopeId 的继承 ## 我们把上面的例子再完善下: ` // 父组件

// 子组件

`
由于我们使用了 scoped 标识进行样式隔离,子组件的 div 不应该有任何背景颜色,可是现实总在狠狠的打脸~~

不知道你的媚眼看到问题的所在了没:
子元素的根元素会继承父元素的 ScopeId!
子元素的根元素会继承父元素的 ScopeId!
子元素的根元素会继承父元素的 ScopeId!(说了三遍的话,肯定很重要)
由于子元素的根元素除了拥有自己的 ScopeId 属性,还继承了父元素的 ScopeId 属性,所以父元素的样式类 bg 对其依然有效

四、怎么破?

破解的方式也很简单,为每一个组件的根元素提供一个另类一点的样式名(如果有的话),例如就不要每个组件都命名为:wrap,根据业务名为:b1-wrap、b2-wrap 等

组件中的非根元素,类名不管怎么命名,怎么重名,都是不会发生污染的,这个自己领悟~~

五、【更新】这不是bug

惭愧,文档查得不够详实,实际上官网已经有:
Be careful with descendant selectors in recursive components! For a CSS rule with the selector .a .b, if the element that matches .a contains a recursive child component, then all .b in that child component will be matched by the rule.

性能优化部分总结

发表于 2018-01-13

1.Minimize HTTP Requests 减少http的请求

合并文件 雪碧图

2.Use a Content Delivery Network 利用CDN技术

CDN内容分发网络 必须有钱

把项目放在阿里云上,买一小块空间

3.Gzip Components Gzip压缩

减少了http请求的大小

自动化工具,边写代码边压缩

4.Put stylesheets at the top 把css放顶部

为了更快渲染页面

5.put script at the bottom 把js放底部

js阻塞加载,一条执行完才会执行另一条

自己的代码一般放顶部,别人的代码放底部

6.将css和js外链

7.Minify Javascript and css 减少js和css的体积

8.Avoid Redirect 避免重定向 每做一次重定向就是重新发送了一次请求

9.Remove Duplicate Scripts 删除重复的脚本

10.用get方式请求ajax,因为post要请求两次

11.Reduce the Number of DOM Elements 减少DOM元素数量 减少DOM操作,能用变量就用变量

12.No 404s 不要出现404页面

13.Reduce Cookie Size 减小cookie cookie特点:每次请求都有cookie

14.优化css,用雪碧图

15.不要在HTML中缩放图片 js重绘重排 css3只重绘

尽量使用css3的运动,减少重排

16.for-in 能用普通循环就用不for in循环(循环json和数组)

17.功能越强大消耗的性能就越高,所以能用Math.floor就不用parseInt,parseInt能字符串转数字,也取整

执行的性能:

1.少用定时器 打开另一个网页的时候 浏览器会改动定时器

2.尽量少操作DOM

3.多用变量(声明变量的时候尽量都写在最前面),预加载

4.尽量能用正则的就不用字符串方法(正则是操作字符串的底层语言)

5.闭包(没用的子函数,释放掉)

性能优化的题:斐波那契数列又称兔子数列,一般解题是

function fn(n){

if(n<=2){

return fn(n-1)+fn(n-2);

}

alert();括号里填想算的数字,这类方法是自己调用自己,递归,本身非常快,但咱们的重复的计算太多了,所以算的数越大时间越长。

所以我们通过吧递归转化为非递归求解的方式,用一个数组存储重复的数据,算出的速度就大大提高了。

var arr=[];

function fn(n){

if(n<=2){

return 1;

}else{

if(arr[n]){

return arr[n];

}else{

arr[n]=fn(n-1)+fn(n-2);

return arr[n];

}

}

}

Canvas基础知识

发表于 2017-12-29

Canvas画布是HTML5的特性,可以制作动画、游戏;
手册文档:https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial

放置一个canvas标签

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style type="text/css">
        canvas{
            border:1px solid #333;
        }
    </style>
</head>
<body>
    <canvas id="mycanvas" width="600" height="400"></canvas>
</body>
</html>

注意,千万不要用css来设置width、height,应该使用canvas标签的属性。

js部分

<script type="text/javascript">
    //得到节点
    var mycanvas = document.getElementById("mycanvas");
    //得到上下文
    var ctx = mycanvas.getContext("2d");

    //绘制一个矩形
    ctx.fillStyle = "blue";
    ctx.fillRect(100 , 100 , 180 , 60);

    //绘制一个圆形
    ctx.fillStyle = "gold";
    ctx.beginPath();
    ctx.arc(390 , 190 , 110 , 0 , Math.PI * 2 , true);
    ctx.fill();
    ctx.strokeStyle = "red";
    ctx.lineWidth = 10;
    ctx.stroke();
    ctx.closePath();
</script>

所有的属性语句,都是进行一些配置

ctx.fillStyle = "blue";
...
ctx.fillStyle = "gold";
....
ctx.strokeStyle = "red";
....
ctx.lineWidth = 10;

所有的方法语句,都是在执行“动令”

ctx.fillRect(100 , 100 , 180 , 60);
....
ctx.arc(390 , 190 , 110 , 0 , Math.PI * 2 , true);
........
ctx.fill();
...
ctx.stroke();

canvas的API确实很简单,常用的属性和方法加起来只有16个。

12
YangYi

YangYi

技术和生活,我融为一体。

14 日志
RSS
GitHub E-Mail Coding.NET Weibo 简书 Instagram
© 2018 YangYi
由 Hexo 强力驱动
|
主题 — NexT.Muse v5.1.4
博客全站共23.1k字