www.91084.com

GVKun编程网logo

关于requireJS的同步加载和异步加载

8

本文将为您提供关于关于requireJS的同步加载和异步加载的详细介绍,同时,我们还将为您提供关于04.01异步加载基础——关于异步加载&数据提交、04.02zTree的异步加载流程——关于异步加载&

本文将为您提供关于关于requireJS的同步加载和异步加载的详细介绍,同时,我们还将为您提供关于04.01 异步加载基础 —— 关于 异步加载 & 数据提交、04.02 zTree 的异步加载流程 —— 关于 异步加载 & 数据提交、AngularJS + ui-router + RequireJS异步加载注册controller/directive/filter/service、define 解析依赖,判断状态,初始化/触发加载 --------require 同步加载(直接返回)/异步加载(创建匿名模块,判断状态,初始化/触发加载)的实用信息。

本文目录一览:

关于requireJS的同步加载和异步加载

关于requireJS的同步加载和异步加载

这篇随笔主要记录require(''name'')和require([''name1'',''name2''])在同步和异步加载使用的区别

1、require(''name'')同步加载模块的形式

 

define(function(require, exports, module) {
        var a = require(''a''),
            b = require(''b'');

        //Return the module value
        return function () {};
    }
);

 

(1)首先看上面的代码,使用了var a = require(''a'')这样的写法,这是一种同步调用模块的写法(因为加载a模块后直接返回而不必放在回调函数中使用), 说明此时在该define函数作用域里,模块a已被加载装配完毕,并可以通过require函数返回a模块,注意此时require函数中使用的参数是模块名而非数组;

 

(2)其次,该define函数是一种commonJS的简化写法,回调函数前并未声明依赖关系的数组,即并define([''require'',''exports'',''module''],function(require, exports, module) {});这样的写法。此时require会使用

Function.prototype.toString() 对回调函数进行解析,并通过解析发现require(''a'')和require(''b'')。由于在调用回调函数之前,require会预先加载模块的所有依赖,所以在调用回调函数前会预先装配a模块和b模块,因此在调用require(''a'')和require(''b'')时,a和b模块已经提前装配好了;

 

(3)此外还需要注意的是,当define函数声明依赖关系数组时,当需要在回调函数使用var a = require(''a'')这样的写法时必须要将所需的模块a添加到依赖关系数组中,因为当define包含依赖关系数组时,require会将依赖关系数组中的依赖视为回调函数所需的所有依赖,即上面的代码就应改为如下形式,否则会报依赖关系没有加载的错误:

define([''require'',''exports'',''module'',''a'',''b''],function(require, exports, module) {
        var a = require(''a'');
            b = require(''b'');

        //Return the module value
        return function () {};
    }
);

 

(4) 由于使用require(''name'')的原理是将所需的依赖预先加载然后再能进行调用,所以不能再全局作用域中使用var a = require(''a'')这样的写法,这样的写法必须包含在define或require([...],function(){})的回调函数中;

 

(5)由于使用commonJS写法时,require检测依赖关系的机制是通过调用Function.prototype.toString() ,所以不能使用以下写法,否则会报依赖关系没有加载的错误:

define(function(require, exports, module) {
        var a = getRequireModule(require, ''a'');
              b = getRequireModule(require, ''b'');

        //Return the module value
        return function () {};
    }
);

function getRequireModule(require, moduleName) {
    return require(moduleName);  
}

 

2、 require([''name1'', ''name2''])异步加载模块的形式

(1)通过require([...])形式获取模块的依赖,和上面不同的是,调用require函数使用的参数是数组而非模块名,这种调用方式是异步调用的方式,即不能使用var a = require([''a''])这样的方式同步返回一个模块,require([''a''])返回的是一个函数,而非a模块向外部暴露的接口,应该在回调函数中使用模块a,即如下的方式才是正确的:

define([''a''], function(a) {
   console.log(a); 
})

 

(2)和require(''a'')的另一个区别是,由于require([''a''])是一种异步依赖模块的方法,所以在使用commonJS简化的define写法时,加载依赖关系时不会检测到[''a'']中所包含的a模块

 

(3)由于异步加载的关系,所以在使用时仍应注意有两种情况:

     1、当依赖的模块遵循AMD规范时,该模块将会被包含在define函数中,会拥有自己的作用域和向外部暴露的接口,需要通过回调函数才能使用这些模块向外提供的接口;

     2、当依赖的模块不遵循AMD规范时,该模块被加载后,由于模块中的js代码具有全局作用域,理论上能够在外部而不必在回调函数中使用模块的接口,但是由于模块是异步加载的,在使用依赖模块提供的接口时,在外部无法保证模块是否已加载完毕,所以仍然应在回调函数中使用依赖模块。

 

(4)当require调用需要使用回调函数时,正确的写法应该是:

    require([''dependency''], function (dependency) {});

           写成require(''dependency'', function (dependency) {});   是错误的

04.01 异步加载基础 —— 关于 异步加载 & 数据提交

04.01 异步加载基础 —— 关于 异步加载 & 数据提交

简介

使用树结构,肯定会有很多同学直接提问:“我的页面如何异步加载节点数据呢?” 这一章将主要针对 zTree 的异步加载进行讲解。

看这篇文档时,你需要对照 API 文档进行学习(http://www.treejs.cn/v3/api.php)

什么是异步加载

使用 zTree 的不少朋友,不仅仅是 zTree 的初学者,更是 前端开发的初学者,对于这部分朋友,请你先去把以下基础内容学习一下:

  • AJAX 教程
  • jQuery 官网的 ajax 文档
  • jQuery ajax 中文参考手册

zTree 与 异步加载

对于异步加载节点数据这一功能, 你可以使用 zTree 的 Ajax,也可以完全不使用。

使用自己的 ajax 方法

  1. 在代码中,根据自己的需求,使用 ajax 获取节点数据, 然后去 init 初始化 zTree 或 在 zTree init 后,使用 addNodes 方法去添加节点
  2. 如果需要实现逐级加载, 那么可以利用 onExpand 回调捕获展开的事件,然后 自己使用 ajax 加载数据,加载后使用 addNodes 方法即可 这里几个非常重要的关键点一定要注意,否则肯定会出问题:
    • 某个父节点加载子节点时,一定要设置状态,避免其在加载过程中,用户反复折叠、展开操作,进行多次加载,导致子节点重复
    • 父节点加载子节点成功后, 再次展开时,就不要再反复进行异步加载,除非你先把子节点清除,然后重新加载

zTree 的 异步加载模式配置

参考Demo:http://www.treejs.cn/v3/demo.php#_108

配置

阅读以下代码时,请务必结合 API 的说明进行理解。

var setting = {
    async: {
        // 开启 zTree 的异步加载模式
        enable: true,
        // 设置 ajax 的 url
        // url 也可以设置为 function,可以针对不同的父节点从不同的接口获取子节点数据
        url:"../asyncData/getNodes.php",
        // 配置节点的属性参数,这些配置的参数将会当作 ajax 的参数传给后端
        autoParam:["id", "name=n", "level=lv"],
        // 配置url 的其他参数,这些参数也会直接当作 ajax 的参数传给后端
        // 如果需要动态修改 otherParam,请利用 beforeAsync 回调 去修改 zTreeObj.setting.async.otherParam 内容
        otherParam:{"otherParam":"zTreeAsyncTest"},
        // contentType 和 dataType 和 type 都是与 ajax 传输 & 接受的数据类型相关
        contentType: ''application/json'',
        dataType: ''text'',
        type: ''post'',
        // dataFilrer 是专门用于在浏览器端获取数据后,将数据传给 zTree 前进行处理的过程。
        // 尤其是当你的服务端无法直接生成 zTree 节点格式的数据时,这个方法尤为重要
        dataFilter:null
    }
};
  • async.url 具体使用请参考 4.03 如何动态更换加载数据的 url
  • async.contentType & dataType & type 具体使用请参考 4.04 如何处理 Ajax 参数提交
  • async.dataFilter 具体使用请参考 4.05 如何预处理节点数据

后台数据接口

后台为 ajax 提供的接口,需要满足的要求就是:

  1. 正确接受 ajax 请求的参数,以便于根据不同的父节点生成不同的子节点数据
  2. 正确生成 js 可以阅读的 JSON 格式字符串 如果你是逐级生成节点数据,一定要给父节点设置属性 isParent = true,否则 zTree 不会把它当作父节点来处理的
//例如:
[
{ "id":"01", "name":"n1", "isParent":true},
{ "id":"02", "name":"n2", "isParent":false},
{ "id":"03", "name":"n3", "isParent":true},
{ "id":"04", "name":"n4", "isParent":false}
]

异步加载的相关回调

参考Demo:http://www.treejs.cn/v3/demo.php#_109

  1. setting.callback.beforeAsync 这是一个在出发 Ajax 之前被触发的回调,主要用于让程序在触发 Ajax 之前处理一些事情,例如修改 otherParam 参数、根据节点控制是否允许异步加载等
  2. setting.callback.onAsyncSuccess 当 Ajax 请求完毕,成功获取数据,并且添加到 zTree 后,会触发此回调。如果你需要在异步加载后做一系列操作,一定要记住此回调
  3. setting.callback.onAsyncError 当 Ajax 请求完毕,Ajax 请求出现错误时,触发此回调,正常情况下此回调基本无意义,但是对于异常处理非常关键!千万不要忽略它的重要性

异步加载的禁忌

1. AJAX 的同步加载

使用异步加载,本身就是为了提升效率,但有的朋友因为搞不清楚异步加载的工作流,从而产生许多程序错误。然后为了解决问题,就直接把异步加载设置为同步模式,这样最严重的问题就是会在加载时导致 js 代码阻塞,并且页面也是完全无法操作。这样做违背了 AJAX 的初衷!! 想具体了解异步加载流程的,请参考 4.02 zTree 的异步加载流程

2. 异步加载变成了无限循环

务必正常设置 异步加载的参数, 并且保证 服务端正常获取对应的参数,切莫每次请求都获取同样的数据! 否则每次都生成同样的一批数据,这只会让你的树无限的加载下去,每次加载的都是相同的节点,展开后又是相同的节点。。。于是你就崩溃了

3. 异步加载 & 全部展开

异步加载模式,一般有两种用法:

  1. 初次加载节点时采用异步加载,但直接加载全部节点数据

    这种情况一般用于不在页面上生成数据,并且节点数据量不大,数据关系简单的情况

  2. 每次异步加载时,只加载当前这一级的节点数据

    这种一般用于有较规范的数据格式,并且数据量较大的情况,所以既然你的数据量很大,也使用了异步加载来实现,就不要再同时使用全部展开功能了!!这也是严重违背了 AJAX 的初衷,你只会让你的程序越来越慢!

    不过,仍然是有一些极端需求的,所以一定要实现这种需求的,请参考Demo:http://www.treejs.cn/v3/demo.php#_512

    另外,如果你有更深的需求,可以参考 4.07 如何自动加载多级节点 和 4.08 如何自动加载某路径的节点

04.02 zTree 的异步加载流程 —— 关于 异步加载 & 数据提交

04.02 zTree 的异步加载流程 —— 关于 异步加载 & 数据提交

简介

使用 zTree 的前端初学者太多了,所以我必须要仔细讲一下异步加载的代码执行过程。

如果你是个老司机,请忽略本篇文章

1. Javascript 的 AJAX 代码执行过程

jQuery 的 ajax 代码举例:(你可以利用浏览器的调试工具查看 console 的输出结果,代码执行顺序一目了然)

console.log(''code start'');
$.ajax({
	url:"your server interface url", // example: "../asyncData/getNodes.php"
	success: function(data) {
		console.log(''success'');
	},
	error: function() {
		console.log(''error'');
	}
});
console.log(''code running'');
var i, j, k;
for (i=0; i< 99999; i++) {
	for (j=0; j< 9999; j++) {
		k = i * j / (i + j);
	}
}
console.log(''code end'');

上面代码执行后的输出结果:

code start
code running
code end
success or error

如果你同时查看 network 你会发现,在输出 code running 的同时,浏览器已经发起了 ajax 请求。

综上所述:发起异步请求后,一定要等异步加载完成后,再执行与异步加载获取数据相关的活动,否则肯定会出现找不到数据的错误结果!

2. zTree 的 异步加载流程

看了前面的讲解,对于那些总是说:“我的数据已经加载了,但是为什么 zTree 得不到数据??”的朋友,应该有了初步认识!

对于使用异步加载获取 zNodes 后,再初始化 zTree 的朋友,一定要在 ajax 的 success 回调里面先获取数据,然后再初始化 zTree!!!

下面讲一下 zTree 与 Ajax(异步加载)的结合方式:

  1. zTree 在内部把 jQuery 的 ajax 封包了一下,通过 setting.async.* 的配置可以对 Ajax 的基本参数进行设置
  2. zTree 提供了 setting.callback.beforeAsync 回调允许用户在 Ajax 请求之前修改 Ajax 的对应设置 或 禁止 Ajax 请求
  3. zTree 提供了 setting.callback.onAsyncSuccess / onAsyncError 两个回调作为 Ajax 的 成功 & 失败 的回调
  4. zTree 对初始化后无子节点的父节点,展开时主动进行异步加载操作,获取子节点
  5. zTree 对 父节点设置了 isAjaxing 属性,用于判断 该父节点是否正进行 Ajax 加载子节点, 从而避免重复发起 Ajax 请求
  6. zTree 对 父节点设置了 zAsync 属性,用于判断 该父节点是否已经进行过 Ajax 加载子节点,如果进行过,则在展开时不会进行异步加载操作

AngularJS + ui-router + RequireJS异步加载注册controller/directive/filter/service

AngularJS + ui-router + RequireJS异步加载注册controller/directive/filter/service

一般情况下我们会将项目所用到的controller/directive/filter/sercive预先加载完再初始化AngularJS模块,但是当项目比较复杂的情况下,应该是打开对应的界面才加载对应的controller等资源,但是AngularJS一旦初始化,之后加载的controller/directive/filter/sercive是不会自动注册到模块上的。用AngularJS + ui-router + RequireJS来构建项目应该是比较常见的,所以我就基于这个条件来看看如何解决这个问题。

目录结构:

HTML结构非常简单,两个链接,分别改变路由切换到不同子页面:

AngularJS + ui-router + RequireJS异步加载注册controller home local

 main.js配置文件路径,初始化模块

fig({ baseUrl: 'js''app': 'app''angular': 'angular.min''router': 'angular-ui-router''router''angular' require(['app'],'myModule'

 

app.js配置路由并返回myModule模块

define(['router'], angular.module("myModule",['ui.router''home'"home""/home"'

这里是home页面

'"local""/local"'

这里是local页面

'  return app; })

 

界面如下,现在可以点击home和local切换到对应的子页面

接下来要做的是,切换到home界面要加载homeCtrl控制器,切换到local页面加载localCtrl控制器,我们将会用到$controllerProvider来手动注册控制器。怎么拿到$controllerProvider到引用呢?

对angular应用来说,模块对象是全局的,正好可以用来保存$controllerProvider的引用

 在app.js文件define内部加上以下代码

app.config(=

 接着在路由中配置要加载的控制器/指令/过滤器/服务

.config(['$stateProvider','$urlRouterProvider','home'"home""/home"'homeCtrl''

{{str}}

'"$q", deferred = 'controller/homeCtrl'"local""/local"'localCtrl' deferred = 'controller/localCtrl'

最后是控制器的写法,为了省事就两个写在一块了

define(['app'],'homeCtrl',cope){ $scope.str = 'home page''localCtrl',cope){ $scope.str = 'local page'

刷新页面, 就可以动态加载controller了。

directive/filter/service的写法类似于controller,不再赘述,自己动手丰衣足食。

3月21日更新:分别写了controller、filter、Service、directive的简单实例放到git上了

By:古德God于 2016/01/15 00:30:47

原文链接:http://www.cnblogs.com/wangmeijian/p/5020788.html

define 解析依赖,判断状态,初始化/触发加载 --------require 同步加载(直接返回)/异步加载(创建匿名模块,判断状态,初始化/触发加载)

define 解析依赖,判断状态,初始化/触发加载 --------require 同步加载(直接返回)/异步加载(创建匿名模块,判断状态,初始化/触发加载)

define

(1)获取依赖 AMD/CMD

(2)触发回调 onScriptLoad

(3)解析依赖

已加载:触发回调

未加载:创建module,监听,触发加载

检查module状态

require 创建匿名模块,加载依赖

今天关于关于requireJS的同步加载和异步加载的介绍到此结束,谢谢您的阅读,有关04.01 异步加载基础 —— 关于 异步加载 & 数据提交、04.02 zTree 的异步加载流程 —— 关于 异步加载 & 数据提交、AngularJS + ui-router + RequireJS异步加载注册controller/directive/filter/service、define 解析依赖,判断状态,初始化/触发加载 --------require 同步加载(直接返回)/异步加载(创建匿名模块,判断状态,初始化/触发加载)等更多相关知识的信息可以在本站进行查询。

本文标签:

上一篇php的数组和json格式的折腾(php 数组 json)

下一篇#JS# 如何判断一个字符串是否为日期格式(#js 判断字符串是否是日期)