皮皮网
皮皮网

【防红源码程序】【人类起源码】【宁河源码】scrollrect源码分析

来源:长安打赏系统源码免费下载 发表时间:2024-11-28 14:40:10

1.Django的源码懒加载是什么(2023年最新解答)
2.精读《webreflow》

scrollrect源码分析

Django的懒加载是什么(2023年最新解答)

       导读:本篇文章首席CTO笔记来给大家介绍有关Django的懒加载是什么的相关内容,希望对大家有所帮助,分析一起来看看吧。源码

Django源码阅读(一)项目的分析生成与启动

       诚实的说,直到目前为止,源码我并不欣赏django。分析防红源码程序在我的源码认知它并不是多么精巧的设计。只是分析由功能堆积起来的"成熟方案"。但每一样东西的源码崛起都是时代的选择。无论你多么不喜欢,分析但它被需要。源码希望有一天,分析python能有更多更丰富的源码成熟方案,且不再被诟病性能和可维护性。分析(屁话结束)

       取其精华去其糟粕,源码人类起源码django的优点是方便,我们这次源码阅读的目的是探究其方便的本质。计划上本次源码阅读不会精细到每一处,而是大体以功能为单位进行解读。

       django-adminstartprojectHelloWorld即可生成django项目,命令行是exe格式的。

       manage.py把参数交给命令行解析。

       execute_from_command_line()通过命令行参数,创建一个管理类。然后运行他的execute()。

       如果设置了reload,将会在启动前先check_errors。

       check_errors()是个闭包,所以上文结尾是宁河源码(django.setup)()。

       直接看最后一句settings.INSTALLED_APPS。从settings中抓取app

       注意,这个settings还不是我们项目中的settings.py。而是一个对象,位于django\conf\__init__.py

       这是个Settings类的懒加载封装类,直到__getattr__取值时才开始初始化。然后从Settings类的实例中取值。且会讲该值赋值到自己的__dict__上(下次会直接在自己身上找到,因为__getattr__优先级较低)

       为了方便debug,我们直接写个run.py。不用命令行的方式。

       项目下建个run.py,模拟runserver命令

       debug抓一下setting_module

       回到setup()中的最后一句apps.populate(settings.INSTALLED_APPS)

       开始看apps.populate()

       首先看这段

       这些App最后都会封装成为AppConfig。且会装载到self.app_configs字典中

       随后,做相册源码分别调用每个appConfig的import_models()和ready()方法。

       App的装载部分大体如此

       为了方便debug我们改写下最后一句

       res的类型是Commanddjango.contrib.staticfiles.management.commands.runserver.Commandobjectat0xEDA0

       重点是第二句,让我们跳到run_from_argv()方法,这里对参数进行了若干处理。

       用pycharm点这里的handle会进入基类的方法,无法得到正确的走向。实际上子类Commond重写了这个方法。

       这里分为两种情况,如果是reload重载时,会直接执行inner_run(),而项目启动需要先执行其他逻辑。

       django项目启动时,实际上会启动两次,如果我们在项目入口(manage.py)中设置个print,源码插装会发现它会打印两次。

       第一次启动时,DJANGO_AUTORELOAD_ENV为None,无法进入启动逻辑。会进入restart_with_reloader()。

       在这里会将DJANGO_AUTORELOAD_ENV置为True,随后重启。

       第二次时,可以进入启动逻辑了。

       这里创建了一个django主线程,将inner_run()传入。

       随后本线程通过reloader.run(django_main_thread),创建一个轮询守护进程。

       我们接下来看django的主线程inner_run()。

       当我们看到wsgi时,django负责的启动逻辑,就此结束了。接下来的工作交由wsgi服务器了

       这相当于我们之前在fastapi中说到的,将fastapi的app交由asgi服务器。(asgi也是django提出来的,两者本质同源)

       那么这个wsgi是从哪来的?让我们来稍微回溯下

       这个settings是一个对象,在之前的操作中已经从settings.py配置文件中获得了自身的属性。所以我们只需要去settings.py配置文件中寻找。

       我们来寻找这个get_wsgi_application()。

       它会再次调用setup(),重要的是,返回一个WSGIHandler类的实例。

       这就是wsgiapp本身。

       load_middleware()为构建中间件堆栈,这也是wsgiapp获取setting信息的唯一途径。导入settings.py,生成中间件堆栈。

       如果看过我之前那篇fastapi源码的,应该对中间件堆栈不陌生。

       app入口→中间件堆栈→路由→路由节点→endpoint

       所以,wsgiapp就此构建完毕,服务器传入请求至app入口,即可经过中间件到达路由进行分发。

       什么时候用懒加载

       1.懒加载基本

       懒加载——也称为延迟加载,即在需要的时候才加载(效率低,占用内存小)。所谓懒加载,写的是其get方法.

       注意:如果是懒加载的话则一定要注意先判断是否已经有了,如果没有那么再去进行实例化

       2.使用懒加载的好处:

       (1)不必将创建对象的代码全部写在viewDidLoad方法中,代码的可读性更强

       (2)每个控件的getter方法中分别负责各自的实例化处理,代码彼此之间的独立性强,松耦合

       3.代码示例

       1//

       2//YYViewController.m

       3//-浏览器初步

       4//

       5//Createdbyappleon-5-.

       6//Copyright(c)年itcase.Allrightsreserved.

       7//

       8

       9#import"YYViewController.h"

       

       #definePOTOIMGW

       #definePOTOIMGH

       #definePOTOIMGX

       #definePOTOIMGY

       

       @interfaceYYViewController()

       

       @property(nonatomic,strong)UILabel*firstlab;

       @property(nonatomic,strong)UILabel*lastlab;

       @property(nonatomic,strong)UIImageView*icon;

       @property(nonatomic,strong)UIButton*leftbtn;

       @property(nonatomic,strong)UIButton*rightbtn;

       @property(nonatomic,strong)NSArray*array;

       @property(nonatomic,assign)inti;

       -(void)change;

       @end

       

       

       

       @implementationYYViewController

       

       -(void)viewDidLoad

       {

       [superviewDidLoad];

       [selfchange];

       }

       

       -(void)change

       {

       [self.firstlabsetText:[NSStringstringWithFormat:@"%d/5",self.i+1]];

       //先get再set

       

       self.icon.image=[UIImageimageNamed:self.array[self.i][@"name"]];

       self.lastlab.text=self.array[self.i][@"desc"];

       

       self.leftbtn.enabled=(self.i!=0);

       self.rightbtn.enabled=(self.i!=4);

       }

       

       //延迟加载

       /**1.的序号标签*/

       -(UILabel*)firstlab

       {

       //判断是否已经有了,若没有,则进行实例化

       if(!_firstlab){

       _firstlab=[[UILabelalloc]initWithFrame:CGRectMake(,,,)];

       [_firstlabsetTextAlignment:NSTextAlignmentCenter];

       [self.viewaddSubview:_firstlab];

       }

       return_firstlab;

       }

       

       /**2.控件的延迟加载*/

       -(UIImageView*)icon

       {

       //判断是否已经有了,若没有,则进行实例化

       if(!_icon){

       _icon=[[UIImageViewalloc]initWithFrame:CGRectMake(POTOIMGX,POTOIMGY,POTOIMGW,POTOIMGH)];

       UIImage*image=[UIImageimageNamed:@"biaoqingdi"];

       _icon.image=image;

       [self.viewaddSubview:_icon];

       }

       return_icon;

       }

       

       /**3.描述控件的延迟加载*/

       -(UILabel*)lastlab

       {

       //判断是否已经有了,若没有,则进行实例化

       if(!_lastlab){

       _lastlab=[[UILabelalloc]initWithFrame:CGRectMake(,,,)];

       [_lastlabsetTextAlignment:NSTextAlignmentCenter];

       [self.viewaddSubview:_lastlab];

       }

       return_lastlab;

       }

       

       /**4.左键按钮的延迟加载*/

       -(UIButton*)leftbtn

       {

       //判断是否已经有了,若没有,则进行实例化

       if(!_leftbtn){

       _leftbtn=[UIButtonbuttonWithType:UIButtonTypeCustom];

       _leftbtn.frame=CGRectMake(0,self.view.center.y,,);

       [_leftbtnsetBackgroundImage:[UIImageimageNamed:@"left_normal"]forState:UIControlStateNormal];

       [_leftbtnsetBackgroundImage:[UIImageimageNamed:@"left_highlighted"]forState:UIControlStateHighlighted];

       [self.viewaddSubview:_leftbtn];

       [_leftbtnaddTarget:selfaction:@selector(leftclick:)forControlEvents:UIControlEventTouchUpInside];

       }

       return_leftbtn;

       

       }

       

       /**5.右键按钮的延迟加载*/

       -(UIButton*)rightbtn

       {

       if(!_rightbtn){

       _rightbtn=[UIButtonbuttonWithType:UIButtonTypeCustom];

       _rightbtn.frame=CGRectMake(POTOIMGX+POTOIMGW+,self.view.center.y,,);

       [_rightbtnsetBackgroundImage:[UIImageimageNamed:@"right_normal"]forState:UIControlStateNormal];

       [_rightbtnsetBackgroundImage:[UIImageimageNamed:@"right_highlighted"]forState:UIControlStateHighlighted];

       [self.viewaddSubview:_rightbtn];

       [_rightbtnaddTarget:selfaction:@selector(rightclick:)forControlEvents:UIControlEventTouchUpInside];

       }

       return_rightbtn;

       }

       

       //array的get方法

       -(NSArray*)array

       {

       if(_array==nil){

       NSString*path=[[NSBundlemainBundle]pathForResource:@"data"ofType:@"plist"];

       _array=[[NSArrayalloc]initWithContentsOfFile:path];

       }

       return_array;

       }

       

       -(void)rightclick:(UIButton*)btn

       {

       self.i++;

       [selfchange];

       }

       

       -(void)leftclick:(UIButton*)btn

       {

       self.i--;

       [selfchange];

       }

       

       @end

什么是预加载、懒加载

       先用占位符表示,不要将地址放到src属性中,而是放到其它属性(data-original)中

       页面加载完成后,监听窗口滚动,当出现在视窗中时再给它赋予真实的地址,也就是将data-original中的属性拿出来放到src属性中

       在滚动页面的过程中,通过给scroll事件绑定lazyload函数,不断的加载出需要的

       注意:请对lazyload函数使用防抖与节流,不懂这两的可以自己去查

       3.可视区加载

       这里也分为两种情况

       1、页面滚动的时候计算的位置与滚动的位置

       2、通过新的API:IntersectionObserverAPI(可以自动"观察"元素是否可见)

       如上,data-属于自定义属性,ele.dataset.可以读取自定义属性集合

       img.srcset属性用于设置不同屏幕密度下,image自动加载不同的,比如imgsrc="image-.png"srcset="image-.png2x"/

       预加载

       提前加载,当用户需要查看时可直接从本地缓存中渲染

       加载方式目前主要有两种

       待到满足触发条件后,再通过JS渲染

       结语:以上就是首席CTO笔记为大家整理的关于Django的懒加载是什么的相关内容解答汇总了,希望对您有所帮助!如果解决了您的问题欢迎分享给更多关注此问题的朋友喔~

精读《webreflow》

       ç½‘页重排(回流)是阻碍流畅性的重要原因之一,结合Whatforceslayout/reflow这篇文章与引用,整理一下回流的起因与优化思考。

       å€Ÿç”¨è¿™å¼ ç»å…¸å›¾ï¼š

       ç½‘页渲染会经历DOM->CSSOM->Layout(重排orreflow)->Paint(重绘)->Composite(合成),其中Composite在精读《深入了解现代浏览器四》详细介绍过,是在GPU进行光栅化。

       é‚£ä¹ˆæŽ’除JS、DOM、CSSOM、Composite可能导致的性能问题外,剩下的就是我们这次关注的重点,reflow了。从顺序上可以看出来,重排后一定重绘,而重绘不一定触发重排。

概述

       ä»€ä¹ˆæ—¶å€™ä¼šè§¦å‘Layout(reflow)呢?一般来说,当元素位置发生变化时就会。但也不尽然,因为浏览器会自动合并更改,在达到某个数量或时间后,会合并为一次reflow,而reflow是渲染页面的重要一步,打开浏览器就一定会至少reflow一次,所以我们不可能避免reflow。

       é‚£ä¸ºä»€ä¹ˆè¦æ³¨æ„reflow导致的性能问题呢?这是因为某些代码可能导致浏览器优化失效,即明明能合并reflow时没有合并,这一般出现在我们用jsAPI访问某个元素尺寸时,为了保证拿到的是精确值,不得不提前触发一次reflow,即便写在for循环里。

       å½“然也不是每次访问元素位置都会触发reflow,在浏览器触发reflow后,所有已有元素位置都会记录快照,只要不再触发位置等变化,第二次开始访问位置就不会触发reflow,关于这一点会在后面详细展开。现在要解释的是,这个”触发位置等变化“,到底有哪些?

       æ ¹æ®Whatforceslayout/reflow文档的总结,一共有这么几类:

获得盒子模型信息

       elem.offsetLeft,elem.offsetTop,elem.offsetWidth,elem.offsetHeight,elem.offsetParent

       elem.clientLeft,elem.clientTop,elem.clientWidth,elem.clientHeight

       elem.getClientRects(),elem.getBoundingClientRect()

       èŽ·å–元素位置、宽高的一些手段都会导致reflow,不存在绕过一说,因为只要获取这些信息,都必须reflow才能给出准确的值。

滚动

       elem.scrollBy(),elem.scrollTo()

       elem.scrollIntoView(),elem.scrollIntoViewIfNeeded()

       elem.scrollWidth,elem.scrollHeight

       elem.scrollLeft,elem.scrollTop访问及赋值

       å¯¹scrollLeft赋值等价于触发scrollTo,所有导致滚动产生的行为都会触发reflow,笔者查了一些资料,目前主要推测是滚动条出现会导致可视区域变窄,所以需要reflow。

focus()

       elem.focus()(源码)

       å¯ä»¥æ ¹æ®æºç çœ‹ä¸€ä¸‹æ³¨é‡Šï¼Œä¸»è¦æ˜¯è¿™ä¸€æ®µï¼š

//Ensurewehavecleanstyle(includingforceddisplaylocks).GetDocument().UpdateStyleAndLayoutTreeForNode(this)

       å³åœ¨èšç„¦å…ƒç´ æ—¶ï¼Œè™½ç„¶æ²¡æœ‰æ‹¿å…ƒç´ ä½ç½®ä¿¡æ¯çš„诉求,但指不定要被聚焦的元素被隐藏或者移除了,此时必须调用UpdateStyleAndLayoutTreeForNode重排重绘函数,确保元素状态更新后才能继续操作。

       è¿˜æœ‰ä¸€äº›å…¶ä»–elementAPI:

       elem.computedRole,elem.computedName

       elem.innerText(源码)

       innerText也需要重排后才能拿到正确内容。

获取window信息

       window.scrollX,window.scrollY

       window.innerHeight,window.innerWidth

       window.visualViewport.height/width/offsetTop/offsetLeft(源码)

       å’Œå…ƒç´ çº§åˆ«ä¸€æ ·ï¼Œä¸ºäº†æ‹¿åˆ°æ­£ç¡®å®½é«˜å’Œä½ç½®ä¿¡æ¯ï¼Œå¿…须重排。

document相关

       document.scrollingElement仅重绘

       document.elementFromPoint

       elementFromPoint因为要拿到精确位置的元素,必须重排。

Form相关

       inputElem.focus()

       inputElem.select(),textareaElem.select()

       focus、select触发重排的原因和elem.focus类似。

鼠标事件相关

       mouseEvt.layerX,mouseEvt.layerY,mouseEvt.offsetX,mouseEvt.offsetY(源码)

       é¼ æ ‡ç›¸å…³ä½ç½®è®¡ç®—,必须依赖一个正确的排布,所以必须触发reflow。

getComputedStyle

       getComputedStyle通常会导致重排和重绘,是否触发重排取决于是否访问了位置相关的key等因素。

Range相关

       range.getClientRects(),range.getBoundingClientRect()

       èŽ·å–选中区域的大小,必须reflow才能保障精确性。

SVG

       å¤§é‡SVG方法会引发重排,就不一一枚举了,总之使用SVG操作时也要像操作dom一样谨慎。

contenteditable

       è¢«è®¾ç½®ä¸ºcontenteditable的元素内,包括将图像复制到剪贴板在内,大量操作都会导致重排。(源码)

精读

       Whatforceslayout/reflow下面引用了几篇关于reflow的相关文章,笔者挑几个重要的总结一下。

repaint-reflow-restyle

       repaint-reflow-restyle提到现代浏览器会将多次dom操作合并,但像IE等其他内核浏览器就不保证有这样的实现了,因此给出了一个安全写法:

//badvarleft=,top=;el.style.left=left+"px";el.style.top=top+"px";//betterel.className+="theclassname";//orwhentopandleftarecalculateddynamically...//betterel.style.cssText+=";left:"+left+"px;top:"+top+"px;";

       æ¯”如用一次className的修改,或一次cssText的修改保证浏览器一定触发一次重排。但这样可维护性会降低很多,不太推荐。

avoidlargecomplexlayouts

       avoidlargecomplexlayouts重点强调了读写分离,首先看下面的badcase:

functionresizeAllParagraphsToMatchBlockWidth(){ //Putsthebrowserintoaread-write-read-writecycle.for(vari=0;i<paragraphs.length;i++){ paragraphs[i].style.width=box.offsetWidth+'px';}}

       åœ¨for循环中不断访问元素宽度,并修改其宽度,会导致浏览器执行N次reflow。

       è™½ç„¶å½“JavaScript运行时,前一帧中的所有旧布局值都是已知的,但当你对布局做了修改后,前一帧所有布局值缓存都会作废,因此当下次获取值时,不得不重新触发一次reflow。

       è€Œè¯»å†™åˆ†ç¦»çš„话,就代表了集中读,虽然读的次数还是那么多,但从第二次开始就可以从布局缓存中拿数据,不用触发reflow了。

       å¦å¤–还提到flex布局比传统float重排速度快很多(3msvsms),所以能用flex做的布局就尽量不要用float做。

reallyfixinglayoutthrashing

       reallyfixinglayoutthrashing提到了用fastdom实践读写分离:

ids.forEach(id=>{ fastdom.measure(()=>{ consttop=elements[id].offsetTopfastdom.mutate(()=>{ elements[id].setLeft(top)})})})

       fastdom是一个可以在不分离代码的情况下,分离读写执行的库,尤其适合用在reflow性能优化场景。每一个measure、mutate都会推入执行队列,并在window.requestAnimationFrame时机执行。

总结

       å›žæµæ— æ³•é¿å…ï¼Œä½†éœ€è¦æŽ§åˆ¶åœ¨æ­£å¸¸é¢‘率范围内。

       æˆ‘们需要学习访问哪些属性或方法会导致回流,能不使用就不要用,尽量做到读写分离。在定义要频繁触发回流的元素时,尽量使其脱离文档流,减少回流产生的影响。

       è®¨è®ºåœ°å€æ˜¯ï¼šç²¾è¯»ã€Šwebreflow》·Issue#·dt-fe/weekly

       å¦‚果你想参与讨论,请点击这里,每周都有新的主题,周末或周一发布。前端精读-帮你筛选靠谱的内容。

       ç‰ˆæƒå£°æ˜Žï¼šè‡ªç”±è½¬è½½-非商用-非衍生-保持署名(创意共享3.0许可证)

原文:/post/

相关栏目:热点