【原】YUI3:js加载过程及时序问题
时序问题在javascript中比较常见,尤其是在网络环境不稳定时以及某些浏览器本来版本中比较多,遇到此类问题,往往会使开发者非常头痛,问题的重现需要特定的环境,是偶发的,不容易重现。对于有经验的开发者,大部分的时序问题都可以在代码中避免,对于浏览器,js代码的执行是单线程的,同一时刻只有一段js代码在执行,js的执行主要是通过两种方式来触发:
- script标签中的代码加载执行:js是解释型语言,从上到下边解释边执行,通常,在模块化的js代码中,我们一般习惯给与一个统一的初始化执行入口。
- 通过事件分发的形式来执行:如按钮点击,鼠标划过等事件触发,主要对应于用户操作dom节点触发,当然,ajax请求回调也属于事件分发形式。
我们看以下代码片段。
代码1:
<script type="text/javascript">
var str = "hello, world";
</script>
<script type="text/javascript">
str = "I was re-defined";
</script>
代码2:
<script type="text/javascript">
var ClassB = {
hello : function(){
alert(str);
}
};
ClassB.hello();
</script>
毫无悬念,这样的执行是没有问题的,此处是第一种触发方式,代码1执行的时候,str已经声明并赋值完毕,如果反过来就是undefind。
再看如下两段代码:
代码1:
<script type="text/javascript">
var str = "hello, world";
YUI().use('io', function(Y){
str = "I was re-defined";
});
</script>
代码2:
<script type="text/javascript">
YUI().use('node', function(Y){
var ClassB = {
hello : function(){
alert(str);
}
};
ClassB.hello();
});
</script>
我们首先想到的应该是弹出的“I was re-defined”,因为str被重定义了, 其实不然,use里的模块不一样,执行alert出来的结果都是不同的。在解释这个问题之前,我们先来分析一下YUI3的加载方式:
YUI3采用分模块按需加载的方式来加载自己的组件,我们使用时只需要将所需使用的模块放到use中,自己代码則是放在一个闭包里面,全局Y对象作为一个参数传过来,就如上面一段代码。这样做的好处是因为YUI组件库本身比较庞大,而我们平时使用时很多功能是用不到的,全部加载显然耗时耗流量,按需动态加载則完美的解决了这个问题。
1. 首先需要引入YUI3的一个基础文件:
<script type="text/javascript" src="http://yui.yahooapis.com/3.2.0/build/yui/yui-min.js"></script>
该文件中定义了一些全局变量,use方法,组件的配置文件的路径(loader-min.js),use执行完成后的回调等,以供后续使用,代码如下图
yui-min中的init方式定义了loaderPath即组件文件的路径,在我们没有使用use方法时,所有的组件都不会加载进来的,就仅仅只有一个yui-min.js文件而已。
2. 我们使用YUI().use('node', function(Y){})方法(该方法在yui-min.js中定义),触发Y.Get.script方法,此时就会加载loader-min.js:
该文件里定义了所有的组件(包括YUI3自带的组件以及用户自定义组件)的名称,依赖模块,路径等,use中使用的所有模块都应该在该文件中有定义,配置如下所示:
3. 根据use中声明的所要加载的模块,结合loader中的模块定义,有依赖模块的将依赖模块也加进来,依赖模块同时也有依赖模块,以此类推,将所有模块都加进来,然后向服务器发送请求,加载请求模块。
4. 请求模块加载完成以后执行回调,执行function(Y){}里面的内容。
整个加载过程的抓包数据如下:
此处是以3.2.0版本为例来说明,在YUI3的新版中将loader-min.js并到了yui-min.js中,可以减少一个请求,anyway,总的流程变化不大。
继续回到我们上面讨论的问题,这里片段2的执行采用的事件驱动触发方式,第一段代码片段和第二段代码片段还是会被浏览器按照从上到下的方式依次解释,此时,YUI整个组件库并没有被下载下来,只是加载了一个配置文件而已。两个代码片段各自获得其所需要加载的模块组件并向服务器发送请求,两个代码片段所需yui模块加载完成的速度是不确定的,从而导致出现上述情况。
这个也是YUI3设计的一个初衷,各个功能块都在各自的闭包里面,彼此独立,互不干扰,这也是模块化的一个目标。在实际应用中,要尽量避免出现上述情况,根据实际情况区分对待:
- 最简单的方式,把代码1与代码2写在同一个use闭包中,这样就不会有问题。
- 代码1在很多场景都会使用,每个js文件中重复定义可维护性会降低。此时,可以将代码1作为一个单独的组件封装起来。有些人会觉得这样代码1虽然有公用性,但也不是很强,封装起来有些浪费,其实按照按需加载的逻辑,作为YUI3的一个组件封装起来并不会使整体的代码非常冗余。
- 如果实在不能写在一个use闭包中,也觉得完全没必要封装,这个时候就采用比较笨重的方法,在代码2中设置一个定时器来跑吧(有人说如果代码1中有错误会导致代码2无法执行,好吧,如果代码1中有错误,你用什么方法都避免不了)。
这种情况发生发代码2的初始化方法函数调用代码1中的方法时会发生,如果代码2中事件事件分发执行的函数(如用户点击事件等,ajax回调)去调用代码1中的方法一般不会有这样的问题,当然,并不是100%不会发生…
【原】YUI3:js加载过程及时序问题的更多相关文章
- DOM加载过程
静态的dom 动态的dom http://blog.csdn.net/cxiaokai/article/details/7552653 一:预编译 解释 js加 ...
- 动态加载JS过程中如何判断JS加载完成
在正常的加载过程中,js文件的加载是同步的,也就是说在js加载的过程中,浏览器会阻塞接下来的内容的解析.这时候,动态加载便显得尤为重要了,由于它是异步加载,因此,它可以在后台自动下载,并不会妨碍其它内 ...
- 优化JS加载时间过长的一种思路
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.背景 去年公司在漳州的一个项目中,现场工程人员反映地图部分出图有点 ...
- linux内核启动以及文件系统的加载过程
Linux 内核启动及文件系统加载过程 当u-boot 开始执行 bootcmd 命令,就进入 Linux 内核启动阶段.普通 Linux 内核的启动过程也可以分为两个阶段.本文以项目中使用的 lin ...
- [f]动态判断js加载完成
在正常的加载过程中,js文件的加载是同步的,也就是说在js加载的过程中,浏览器会阻塞接下来的内容的解析.这时候,动态加载便显得尤为重要了,由于它是异步加载,因此,它可以在后台自动下载,并不会妨碍其它内 ...
- js加载优化三
Javascript性能优化之异步加载和执行 Author:小欧2013-09-17 随着科技的发展,如今的网站和五六年前相比,现在的人们对web的要求越来越高了,用户体验,交互效果,视觉效果等等都有 ...
- AngularJS进阶(三十九)基于项目实战解析ng启动加载过程
基于项目实战解析ng启动加载过程 前言 在AngularJS项目开发过程中,自己将遇到的问题进行了整理.回过头来总结一下angular的启动过程. 下面以实际项目为例进行简要讲解. 1.载入ng库 2 ...
- java程序的加载过程
昨天笔试阿里有个求java程序加载过程的题目很是复杂,回来研究了好久才有点明白,整理一下.原题代码如下,判断输出: public class StaticTest { public static in ...
- 动态符号链接的细节 与 linux程序的加载过程
转: http://hi.baidu.com/clivestudio/item/4341015363058d3d32e0a952 值得玩味的一篇分析程序链接.装载.动态链接细节的好文档 导读: by ...
随机推荐
- VS2010 配置 DirectX 开发环境
1.首先下载 DXSDK 并安装 http://download.microsoft.com/download/A/E/7/AE743F1F-632B-4809-87A9-AA1BB3458E31/D ...
- IE8下的项目在IE11下某些功能无法实现的问题
在IE8和IE11 下获取数据的时间进行判断有些不同,也要根据浏览器的版本判断分别实现 $(".btndelete").children().children().click(fu ...
- Yii系列总结:yii 标签用法
yii 常用标签:label标签.文本标签.error标签.textarea标签.hidden标签.password标签.url标签.radio标签.file标签.button标签.checkBox标 ...
- 当 IDENTITY_INSERT 设置为 OFF 时,不能为表 'tb_MyInvoices' 中的标识列插入显式值
默认情况下,IDENTITY_INSER就是off 这种情况下,你写insert 语句时,identity栏位,不要写值,系统会自动帮你写入. 举例说明: ,),dt datetime,pay int ...
- SQL Server数据库空间管理 (1)
数据库经常遇到的问题: 1).数据库文件空间用尽 2).日志文件不停增长 3).数据库文件无法收缩 4).自动增长和自动收缩 本系列就以上面的4个问题入手分析并总结数据库空间的管理方法. 1. ...
- Delphi利用Webbrowser登陆QQ群文档
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms ...
- grok 正则捕获(就是perl的正则捕获)
2.3.2 grok 正则捕获: \s+ 和 [\n\t\r\f]+ 一样 1.命名分组格式为(?<grp name>),反向引用时用\k<grp name> 2.命名分组的匹 ...
- __declspec(dllimport)的作用
是时候总结一下__declspec(dllimport)的作用了.可能有人会问:__declspec(dllimport)和__declspec(dllexport)是一对的,在动态链接库中__dec ...
- 基础巩固(二)- log4j的使用
日志是应用软件中不可缺少的部分,Apache的开源项目log4j是一个功能强大的日志组件,提供方便的日志记录.在apache网站:jakarta.apache.org/log4j 可以免费下载到Log ...
- [Leetcode][Python]47: Permutations II
# -*- coding: utf8 -*-'''__author__ = 'dabay.wang@gmail.com' 47: Permutations IIhttps://oj.leetcode. ...