时序问题在javascript中比较常见,尤其是在网络环境不稳定时以及某些浏览器本来版本中比较多,遇到此类问题,往往会使开发者非常头痛,问题的重现需要特定的环境,是偶发的,不容易重现。对于有经验的开发者,大部分的时序问题都可以在代码中避免,对于浏览器,js代码的执行是单线程的,同一时刻只有一段js代码在执行,js的执行主要是通过两种方式来触发:

  1. script标签中的代码加载执行:js是解释型语言,从上到下边解释边执行,通常,在模块化的js代码中,我们一般习惯给与一个统一的初始化执行入口。
  2. 通过事件分发的形式来执行:如按钮点击,鼠标划过等事件触发,主要对应于用户操作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. 最简单的方式,把代码1与代码2写在同一个use闭包中,这样就不会有问题。
  2. 代码1在很多场景都会使用,每个js文件中重复定义可维护性会降低。此时,可以将代码1作为一个单独的组件封装起来。有些人会觉得这样代码1虽然有公用性,但也不是很强,封装起来有些浪费,其实按照按需加载的逻辑,作为YUI3的一个组件封装起来并不会使整体的代码非常冗余。
  3. 如果实在不能写在一个use闭包中,也觉得完全没必要封装,这个时候就采用比较笨重的方法,在代码2中设置一个定时器来跑吧(有人说如果代码1中有错误会导致代码2无法执行,好吧,如果代码1中有错误,你用什么方法都避免不了)。

这种情况发生发代码2的初始化方法函数调用代码1中的方法时会发生,如果代码2中事件事件分发执行的函数(如用户点击事件等,ajax回调)去调用代码1中的方法一般不会有这样的问题,当然,并不是100%不会发生…

【原】YUI3:js加载过程及时序问题的更多相关文章

  1. DOM加载过程

    静态的dom   动态的dom             http://blog.csdn.net/cxiaokai/article/details/7552653     一:预编译   解释 js加 ...

  2. 动态加载JS过程中如何判断JS加载完成

    在正常的加载过程中,js文件的加载是同步的,也就是说在js加载的过程中,浏览器会阻塞接下来的内容的解析.这时候,动态加载便显得尤为重要了,由于它是异步加载,因此,它可以在后台自动下载,并不会妨碍其它内 ...

  3. 优化JS加载时间过长的一种思路

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.背景 去年公司在漳州的一个项目中,现场工程人员反映地图部分出图有点 ...

  4. linux内核启动以及文件系统的加载过程

    Linux 内核启动及文件系统加载过程 当u-boot 开始执行 bootcmd 命令,就进入 Linux 内核启动阶段.普通 Linux 内核的启动过程也可以分为两个阶段.本文以项目中使用的 lin ...

  5. [f]动态判断js加载完成

    在正常的加载过程中,js文件的加载是同步的,也就是说在js加载的过程中,浏览器会阻塞接下来的内容的解析.这时候,动态加载便显得尤为重要了,由于它是异步加载,因此,它可以在后台自动下载,并不会妨碍其它内 ...

  6. js加载优化三

    Javascript性能优化之异步加载和执行 Author:小欧2013-09-17 随着科技的发展,如今的网站和五六年前相比,现在的人们对web的要求越来越高了,用户体验,交互效果,视觉效果等等都有 ...

  7. AngularJS进阶(三十九)基于项目实战解析ng启动加载过程

    基于项目实战解析ng启动加载过程 前言 在AngularJS项目开发过程中,自己将遇到的问题进行了整理.回过头来总结一下angular的启动过程. 下面以实际项目为例进行简要讲解. 1.载入ng库 2 ...

  8. java程序的加载过程

    昨天笔试阿里有个求java程序加载过程的题目很是复杂,回来研究了好久才有点明白,整理一下.原题代码如下,判断输出: public class StaticTest { public static in ...

  9. 动态符号链接的细节 与 linux程序的加载过程

    转: http://hi.baidu.com/clivestudio/item/4341015363058d3d32e0a952 值得玩味的一篇分析程序链接.装载.动态链接细节的好文档 导读: by ...

随机推荐

  1. 【SSH进阶之路】Hibernate基本原理(一)

    在开始学Hibernate之前,一直就有人说:Hibernate并不难,无非是对JDBC进一步封装.一句不难,难道是真的不难还是眼高手低? 如果只是停留在使用的层面上,我相信什么技术都不难,看看别人怎 ...

  2. Android布局控件

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout ...

  3. vs2012配置opencv及简单测试

    为visual studio2012搭建openCV平台,实现打开图片. 实现步骤: 1.1.配置环境变量 基于win7操作系统的环境配置步骤: 1.1.1 计算机—>属性—>更改设置—& ...

  4. php中Maximum execution time of 120 seconds exceeded时间超时错误解决方案

    1.修改php的配置文件,找到php.ini文件 max_execution_time = 120 ;//设置成你想要的值,单位是秒 2.使用ini_set()函数,使用这个函数来改变你的最大执行时间 ...

  5. Windows下Redis的安装

    1.安装Redis 官方网站:http://redis.io/ 官方下载:http://redis.io/download 可以根据需要下载不同版本 windows版:https://github.c ...

  6. github proxy

    --set github proxy git config --global http.proxy http://user_name:user_pwd@user_ip:port git config  ...

  7. 如何实现button像a标签一样跳转页面

    这个实现起来很简单,如下: <a href="{% url 'cms:add' %}"> <button class="btn btn-default& ...

  8. django models 类型整理 version:1.8.3

    django models 类型整理 version:1.8.3 网上百度到的最上面的一篇已经是11年的了,django变化很大,现在把1.8.3版的models类型大致整理了下贴出来 普通键部分 F ...

  9. SQL Server 造成cpu 使用率高的 6 原因

    第一种: 编译和重编译执行计划. 第二种: 排序与聚合. 第三种: 表格连接操作. 第四种: max degree of parallelism. 第五种: max worker threads. 第 ...

  10. 学习笔记之--MySQL图形界面软件Navicat Premium的安装

    最近因项目开发需要,搁置已久的MySQL再次用到.由于以前都是使用命令行进行操作的,没有图形界面.经同学介绍,安装了一个MySQL的图形界面软件.各种数据库的操作也变得直观方便了很多.现在记录下来,一 ...