首页 文章 精选 留言 我的

精选列表

搜索[性能],共10011篇文章
优秀的个人博客,低调大师

JS异步与性能

一、背景 看了《你不知道的javascript》上卷以及中卷之后,总结一下js的event机制。 二、事件循环 JavaScript 引擎并不是独立运行的,它运行在宿主环境中,对多数开发者来说通常就是Web 浏览器。处理程序中多个块的执行,且执行每块时调用JavaScript 引擎,这种机制被称为事件循环。 先通过一段伪代码了解一下这个概念: // eventLoop是一个用作队列的数组 // (先进,先出) var eventLoop = [ ]; var event; // “永远”执行 while (true) { // 一次tick if (eventLoop.length > 0) { // 拿到队列中的下一个事件 event = eventLoop.shift(); // 现在,执行下一个事件 try { event(); } catch (err) { reportError(err); } } } 这里可以看到,有一个用while 循环实现的持续运行的循环,循环的每一轮称为一个tick。对每个tick 而言,如果在队列中有等待事件,那么就会从队列中摘下一个事件并执行。这些事件称之为回调函数。 一定要清楚,setTimeout(..) 并没有把你的回调函数挂在事件循环队列中。它所做的是设定一个定时器。当定时器到时后,宿主环境会把你的回调函数放在事件循环中,这样,在未来 某个时刻的tick 会摘下并执行这个回调。 如果这时候事件循环中已经有20 个项目了会怎样呢?你的回调就会等待。它得排在 其他项目后面——通常没有抢占式的方式支持直接将其排到队首。这也解释了为什么 setTimeout(..) 定时器的精度可能不高。大体说来,只能确保你的回调函数不会在指定的 时间间隔之前运行,但可能会在那个时刻运行,也可能在那之后运行,要根据事件队列的 状态而定。 回调 listen("click", function handler(evt){ setTimeout( function request(){ ajax( "http://some.url.1", function response(text){ if (text == "hello") { handler(); } else if (text == "world") { request(); } } ); }, 500) ; } ); 这里我们得到了三个函数嵌套在一起构成的链,其中每个函数代表异步序列(任务,“进程”)中的一个步骤。这种代码常常被称为回调地狱(callback hell),有时也被称为毁灭金字塔(pyramid of doom,得名于嵌套缩进产生的横向三角形状)。 线性跟踪 doA( function(){ doB(); doC( function(){ doD(); } ) doE(); } ); doF(); 执行顺序是? A、F、B、C、E、D 在线性(顺序)地追踪这段代码的过程中,我们不得不从一个函数跳到下一个,再跳到下一个,在整个代码中跳来跳去以“查看”流程。而且别忘了,这还是简化的形式,只考虑了最优情况。我们都知道,真实的异步JavaScript程序代码要混乱得多,这使得这种追踪的难度会成倍增加。 我们的顺序阻塞式的大脑计划行为无法很好地映射到面向回调的异步代码。这就是回调方式最主要的缺陷:对于它们在代码中表达异步的方式,我们的大脑需要努力才能同步得上。 信任问题 // A ajax( "..", function(..){ // C } ); // B 这是回调驱动设计最严重(也是最微妙)的问题。它以这样一个思路为中心:有时候ajax(..)(也就是你交付回调continuation 的第三方)不是你编写的代码,也不在你的直接控制下。多数情况下,它是某个第三方提供的工具。 回调设计 (1)为了更优雅地处理错误,有些API 设计提供了分离回调(一个用于成功通知,一个用于出错通知): function success(data) {} function error(data) {} ajax('...', success(data), error(data)); (2)还有一种常见的回调模式叫作“error-first 风格”(有时候也称为“Node 风格”,因为几乎所有Node.js API 都采用这种风格),其中回调的第一个参数保留用作错误对象(如果有的话)。如果成功的话,这个参数就会被清空/ 置假(后续的参数就是成功数据)。不过,如果产生了错误结果,那么第一个参数就会被置起/ 置真(通常就不会再传递其他结果): function respon(err, data) { if(err){ // error } else { // success } } ajax('...', respon); setTimeout 教科书里面的setTimeout 定义很简单setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式。广泛应用场景:定时器,轮播图,动画效果,自动滚动等等。但是setTimeout真的有那么简单吗? for(var i=1; i<=5; i++) { setTimeout(function timer() { console.log(i); }, i*1000); } 结果:以一秒的频率连续输出五个6 解答 1、作用域这里我引用《你不知道的javascript》中的一个比喻,可以把作用域链想象成一座高楼,第一层代表当前执行作用域,楼的顶层代表全局作用域。我们在查找变量时会先在当前楼层进行查找,如果没有找到,就会坐电梯前往上一层楼,如果还是没有找到就继续向上找,以此类推。到达顶层后(全局作用域),可能找到了你所需的变量,也可能没找到,但无论如何查找过程都将停止。 2、任务队列事件循环只有一个,但任务队列可能有多个,任务队列可分为宏任务(macro-task)和微任务(micro-task)。XHR回调、事件回调(鼠标键盘事件)、setImmediate、setTimeout、setInterval、indexedDB数据库操作等I/O以及UI rendering都属于宏任务(也有文章说UI render不属于宏任务,目前还没有定论),process.nextTick、Promise.then、Object.observer(已经被废弃)、MutationObserver(html5新特性)属于微任务。注意进入到任务队列的是具体的执行任务的函数。比如上述例子setTimeout()中的timer函数。另外不同类型的任务会分别进入到他们所属类型的任务队列,比如所有setTimeout()的回调都会进入到setTimeout任务队列,所有then()回调都会进入到then队列。当前的整体代码我们可以认为是宏任务。事件循环从当前整体代码开始第一次事件循环,然后再执行队列中所有的微任务,当微任务执行完毕之后,事件循环再找到其中一个宏任务队列并执行其中的所有任务,然后再找到一个微任务队列并执行里面的所有任务,就这样一直循环下去。 参考资料 《你不知道的javascript》

优秀的个人博客,低调大师

Android性能优化:ViewStub

在开发应用程序的时候,经常会遇到这样的情况,会在运行时动态根据条件来决定显示哪个View或某个布局。那么最通常的想法就是把可能用到的View都写在上面,先把它们的可见性都设为View.GONE,然后在代码中动态的更改它的可见性。这样的做法的优点是逻辑简单而且控制起来比较灵活。但是它的缺点就是耗费资源。虽然把View的初始可见View.GONE但是在Inflate布局的时候View仍然会被Inflate,也就是说仍然会创建对象,会被实例化,会被设置属性。也就是说,会耗费内存等资源。 推荐的做法是使用Android.view.ViewStub,ViewStub是一个轻量级的View,占用资源非常小的控件。在Inflate布局的时候,只有ViewStub会被初始化,然后当ViewStub被设置为可见的时候(默认是不可见的),或是调用了ViewStub.inflate()的时候,ViewStub所向的布局就才会被Inflate和实例化。 但ViewStub也不是万能的,下面总结下ViewStub能做的事儿和什么时候该用ViewStub,什么时候该用可见性的控制。 首先来说说ViewStub的一些特点: (1) ViewStub只能Inflate一次,之后ViewStub对象会被置为空。按句话说,某个被ViewStub指定的布局被Inflate后,就不会够再通过ViewStub来控制它了。 (2) ViewStub只能用来Inflate一个布局文件,而不是某个具体的View,当然也可以把View写在某个布局文件中。 基于以上的特点,那么可以考虑使用ViewStub的情况有: (1) 在程序的运行期间,某个布局在Inflate后,就不会有变化,除非重新启动。 因为ViewStub只能Inflate一次,之后会被置空,所以无法指望后面接着使用ViewStub来控制布局。所以当需要在运行时不止一次的显示和隐藏某个布局,那么ViewStub是做不到的。这时就只能使用View来控制了。 (2) 想要控制显示与隐藏的是一个布局文件,而非某个View。 因为设置给ViewStub的只能是某个布局文件的Id,所以无法让它来控制某个View。 所以,如果想要控制某个View(如Button或TextView)的显示与隐藏,或者想要在运行时不断的显示与隐藏某个布局或View,只能使用View来控制。 下面来看一个实例 在这个例子中,要显示二种不同的布局,一个是用TextView显示一段文字,另一个则是用ImageView显示一个图片。这二个是在onCreate()时决定是显示哪一个,这里就是应用ViewStub的最佳地点。 先来看看布局,一个是主布局,里面只定义二个ViewStub,一个用来控制TextView一个用来控制ImageView,另外就是一个是为显示文字的做的TextView布局,一个是为ImageView而做的布局: 1<?xmlversion="1.0"encoding="utf-8"?>2<LinearLayout 3xmlns:android="http://schemas.android.com/apk/res/android"4android:orientation="vertical"5android:layout_width="fill_parent"6android:layout_height="fill_parent"7android:gravity="center_horizontal">8<ViewStub 9android:id="@+id/viewstub_demo_text"10android:layout_width="wrap_content"11android:layout_height="wrap_content"12android:layout_marginLeft="5dip"13android:layout_marginRight="5dip"14android:layout_marginTop="10dip"15android:layout="@layout/viewstub_demo_text_layout"/>16<ViewStub 17android:id="@+id/viewstub_demo_image"18android:layout_width="wrap_content"19android:layout_height="wrap_content"20android:layout_marginLeft="5dip"21android:layout_marginRight="5dip"22android:layout="@layout/viewstub_demo_image_layout"/>23</LinearLayout> 1//...2@Override 3publicvoidonCreate(BundlesavedInstanceState){ 4super.onCreate(savedInstanceState); 5setContentView(R.layout.viewstub_demo_activity); 6if((((int)(Math.random()*100))&0x01)==0){ 7ViewStubstub=(ViewStub)findViewById(R.id.viewstub_demo_text);//获取布局8stub.inflate();//实例化910TextViewtext=(TextView)findViewById(R.id.viewstub_demo_textview); 11text.setText("HelloWorld"); 12}else{ 13ViewStubstub=(ViewStub)findViewById(R.id.viewstub_demo_image); 14stub.inflate();1516ImageViewimage=(ImageView)findViewById(R.id.viewstub_demo_imageview); 17image.setImageResource(R.drawable.img); 18} 19}20//... 还有类似新内容、新功能提示,这种只会显示一次,且不会发生变化的ViewStub都是挺适合的 本文转自lzwxx 51CTO博客,原文链接:http://blog.51cto.com/13064681/1948196

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册