1.Django的源码懒加载是什么(2023年最新解答)
2.精读ãwebreflowã
Django的懒加载是什么(2023年最新解答)
导读:本篇文章首席CTO笔记来给大家介绍有关Django的懒加载是什么的相关内容,希望对大家有所帮助,分析一起来看看吧。源码Django源码阅读(一)项目的分析生成与启动诚实的说,直到目前为止,源码我并不欣赏django。分析delphi微信源码在我的源码认知它并不是多么精巧的设计。只是分析由功能堆积起来的"成熟方案"。但每一样东西的源码崛起都是时代的选择。无论你多么不喜欢,分析但它被需要。源码希望有一天,分析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字典中
随后,空降app源码资源分别调用每个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ã
getComputedStylegetComputedStyleé常ä¼å¯¼è´éæåéç»ï¼æ¯å¦è§¦åéæåå³äºæ¯å¦è®¿é®äºä½ç½®ç¸å ³çkeyçå ç´ ã
Rangeç¸å ³range.getClientRects(),range.getBoundingClientRect()
è·åéä¸åºåç大å°ï¼å¿ é¡»reflowæè½ä¿é精确æ§ã
SVG大éSVGæ¹æ³ä¼å¼åéæï¼å°±ä¸ä¸ä¸æ举äºï¼æ»ä¹ä½¿ç¨SVGæä½æ¶ä¹è¦åæä½domä¸æ ·è°¨æ ã
contenteditable被设置为contenteditableçå ç´ å ï¼å æ¬å°å¾åå¤å¶å°åªè´´æ¿å¨å ï¼å¤§éæä½é½ä¼å¯¼è´éæã(æºç )
精读Whatforceslayout/reflowä¸é¢å¼ç¨äºå ç¯å ³äºreflowçç¸å ³æç« ï¼ç¬è æå 个éè¦çæ»ç»ä¸ä¸ã
repaint-reflow-restylerepaint-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çä¿®æ¹ä¿è¯æµè§å¨ä¸å®è§¦åä¸æ¬¡éæãä½è¿æ ·å¯ç»´æ¤æ§ä¼éä½å¾å¤ï¼ä¸å¤ªæ¨èã
avoidlargecomplexlayoutsavoidlargecomplexlayoutséç¹å¼ºè°äºè¯»åå离ï¼é¦å çä¸é¢ç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åã
reallyfixinglayoutthrashingreallyfixinglayoutthrashingæå°äºç¨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/