dojo/request
dojo/request模块整体架构解析
总体说明
做前端当然少不了ajax的使用,使用dojo的童鞋都知道dojo是基于模块化管理的前端框架,其中对ajax的处理位于dojo/request模块。一般情况下我们使用ajax请求只需要引入dojo/request模块,然后按照文档的说明制定参数即可。实际上dojo在这一模块的处理中抽象了很多概念:
- 平台侦探器:dojo/request/default
- 请求分发器:dojo/request/registry
- 全局通知器:dojo/request/notify
- 数据传输器:dojo/request/xhr dojo/request/script dojo/request/iframe dojo/request/node
- 数据转化器:dojo/request/handlers
处理器的总体关系如下图所示:

正是这些概念使得dojo在ajax请求上能够提供强大的扩展性和简捷的接口。
Provider
请求传输器被称为Provider,dojo框架自身提供了以下4个provider
- dojo/request/xhr 提供跨浏览器的XMLHttpRequest,在浏览器端它被作为默认的provider
- dojo/request/node 用于node平台的异步请求,在node下呗当做默认的provider。dojo是可以运行在node平台下的,当然需要做一些配置,这是另一篇文章的主要内容
- dojo/request/iframe 不刷新浏览器传输form表单,在文件上传时经常用到
- dojo/request/script 常以jsonp方式来进行跨域请求
所有dojo自带的Provider返回一个promise对象,其中有一个不在标准规范内的属性:response。该属性是一个标准promise对象,该对象将一个代表服务器端响应结果的对象作为fulfill状态的值。这个对象有以下几个属性:



关于这几个Provider的详细讲解请继续关注下一篇文章
default
一般情况下我们发送ajax请求时只需引入dojo/request即可,实际上这是在default中根据不同的运行平台自动给我们提供了一个默认的provider。
1 define([
2 'exports',
3 'require',
4 '../has'
5 ], function(exports, require, has){
6 //读取dojoConfig中的配置信息
7 var defId = has('config-requestProvider'),
8 platformId;
9
10 //根据不同平台选择不同的provider
11 if(has('host-browser') || has('host-webworker')){
12 platformId = './xhr';
13 }else if(has('host-node')){
14 platformId = './node';
15 /* TODO:
16 }else if(has('host-rhino')){
17 platformId = './rhino';
18 */
19 }
20
21 if(!defId){
22 defId = platformId;
23 }
24
25 exports.getPlatformDefaultId = function(){
26 return platformId;
27 };
28 //作为插件使用,是跟参数选择provider
29 exports.load = function(id, parentRequire, loaded, config){
30 require([id == 'platform' ? platformId : defId], function(provider){
31 loaded(provider);
32 });
33 };
34 });
代码中关于exports跟require模块的说明请看我的上一篇博客:require、module、exports dojo中的三个特殊模块标识。
上述内容关于load的函数的出现,意味着该模块可以作为“插件”使用。dojo插件主要用于加载一些非AMD的资源,比如css、html。dojo中常用的插件有5个:
- dojo/domReady
- dojo/text 用于加载静态资源文件
- dojo/i18n 加载国际化语言文件
- dojo/has 用于特性检测
- dojo/require
当在define或require中一个模块引用包含一个!,dojo的加载器会自动将这个模块引用字符串在!处分开,左边部分作为一个模块引用对待,右边部分,等待左边模块加载完毕后交由模块的load方法处理;
exports.load = function(id, parentRequire, loaded, config){
require([id == 'platform' ? platformId : defId], function(provider){
loaded(provider);
});
};
关于load函数的几个参数:
- id:代表!右侧部分
- parentRequire:上下文智能的require请求器
- loaded:id模块加载完毕后的回调
- config:猜测是dojo/_base/config
后三个参数是dojo自己来处理,一般情况下我们不需要关心。
notify
notify是全局的ajax事件通知器,负责全局范围内的ajax事件监听,有类似于jquery中ajaxStart、ajaxComplete的事件。
1 define(['../Evented', '../_base/lang', './util'], function(Evented, lang, util){
2 // module:
3 // dojo/request/notify
4 // summary:
5 // Global notification API for dojo/request. Notifications will
6 // only be emitted if this module is required.
7 //
8 // | require('dojo/request', 'dojo/request/notify',
9 // | function(request, notify){
10 // | notify('load', function(response){
11 // | if(response.url === 'someUrl.html'){
12 // | console.log('Loaded!');
13 // | }
14 // | });
15 // | request.get('someUrl.html');
16 // | }
17 // | );
18
19 var pubCount = 0,
20 slice = [].slice;
21 //实例化dojo/Evented对象,负责分发事件
22 var hub = lang.mixin(new Evented, {
23 onsend: function(data){
24 if(!pubCount){
25 this.emit('start');
26 }
27 pubCount++;
28 },
29 _onload: function(data){
30 this.emit('done', data);
31 },
32 _onerror: function(data){
33 this.emit('done', data);
34 },
35 _ondone: function(data){
36 if(--pubCount <= 0){
37 pubCount = 0;
38 this.emit('stop');
39 }
40 },
41 emit: function(type, event){
42 var result = Evented.prototype.emit.apply(this, arguments);
43
44 // After all event handlers have run, run _on* handler
45 //运行完标准事件处理函数后,再来运行本身的私有函数。
46 //load和error事件处理完后触发done事件
47 //done事件处理完毕后,再来运行本身的_ondone函数,然后触发stop事件
48 if(this['_on' + type]){
49 this['_on' + type].apply(this, slice.call(arguments, 1));
50 }
51 return result;
52 }
53 });
54
55 function notify(type, listener){
56 // summary:
57 // Register a listener to be notified when an event
58 // in dojo/request happens.
59 // type: String?
60 // The event to listen for. Events emitted: "start", "send",
61 // "load", "error", "done", "stop".
62 // listener: Function?
63 // A callback to be run when an event happens.
64 // returns:
65 // A signal object that can be used to cancel the listener.
66 // If remove() is called on this signal object, it will
67 // stop the listener from being executed.
68 return hub.on(type, listener);
69 }
70 notify.emit = function(type, event, cancel){
71 return hub.emit(type, event, cancel);
72 };
73
74 // Attach notify to dojo/request/util to avoid
75 // try{ require('./notify'); }catch(e){}
76 return util.notify = notify;
77 });
最后的一句:util.notify= notify; util将notify与provider关联起来。
registry
该模块可以在不同的情况下使用不同的provider;匹配的条件可以是正则表达式、字符串或者函数。通过registry可以根据不同的条件注册不同的provider。
1 require(["dojo/request/registry", "dojo/Deferred"], function(request, Deferred){
2 request.register("crossdomain/ie", xdrProvider);
3
4 var xdrProvider = function(url, options){
5 var def = new Deferred();
6 xdr = new XDomainRequest();
7 if (xdr) {
8 xdr.onerror = function(){
9 def.reject('error');
10 };
11 xdr.ontimeout = function(){
12 def.reject('timeout');
13 };
14 xdr.onprogress = function(){
15 def.progress('progress');
16 };
17 xdr.onload = function(res){
18 def.resolve(res);
19 };
20 xdr.timeout = 6000;
21 xdr.open(options.method, url);
22 xdr.send(serilize(options.data));
23 } else {
24 def.reject("Failed to create");
25 }
26
27 return def;
28 }
29
30 request.get("crossdomain/ie/getData", {
31 method: "get",
32 data:{id:'ie9'}
33 }).then(function(text){
34 // Do something with the response
35 });
36
37 });
以下便是registry的源码:
define([
'require',
'../_base/array',
'./default!platform',//想想notify中的load函数
'./util'
], function(require, array, fallbackProvider, util){
var providers = []; function request(url, options){
var matchers = providers.slice(0),//作用类似clone
i = 0,
matcher; while(matcher=matchers[i++]){
if(matcher(url, options)){//匹配provider
return matcher.request.call(null, url, options);
}
}
//fallbackProvider由default根据不同平台注入默认的provider
return fallbackProvider.apply(null, arguments);
} function createMatcher(match, provider){
var matcher; if(provider){
if(match.test){
// RegExp
matcher = function(url){
return match.test(url);
};
}else if(match.apply && match.call){
matcher = function(){
return match.apply(null, arguments);
};
}else{
matcher = function(url){
return url === match;
};
} matcher.request = provider;
}else{
// If only one argument was passed, assume it is a provider function
// to apply unconditionally to all URLs
matcher = function(){
return true;
}; matcher.request = match;
} return matcher;
} request.register = function(url, provider, first){
var matcher = createMatcher(url, provider);
providers[(first ? 'unshift' : 'push')](matcher); return {
remove: function(){
var idx;
if(~(idx = array.indexOf(providers, matcher))){
providers.splice(idx, 1);
}
}
};
};
//这里意味着registry也可以使用插件的写法,作用是替换一个默认的provider
request.load = function(id, parentRequire, loaded, config){
if(id){
// if there's an id, load and set the fallback provider
require([id], function(fallback){
fallbackProvider = fallback;//js中的词法作用域,load中永远能够访问到fallbackProvider变量。
loaded(request);
});
}else{
loaded(request);
}
}; util.addCommonMethods(request); return request;
});
handlers
XMLHttpRequest对象请求成功后返回的数据格式只有text跟xml两种,handlers根据request中指定的handleAs参数将请求成功后的数据转化为指定类型。与jquery中的类型转化器作用类似。
dojo中提供了以下三种数据转化器:

此外,handlers有跟registry类似的register方法,可以让我们自定义数据转化器。
1 require(["dojo/request/handlers", "dojo/request", "dojo/dom", "dojo/dom-construct", "dojo/json",
2 "dojo/on", "dojo/domReady!"],
3 function(handlers, request, dom, domConst, JSON, on){
4 handlers.register("custom", function(response){
5 var data = JSON.parse(response.text);
6 data.hello += "!";
7 return data;
8 });
9
10 on(dom.byId("startButton"), "click", function(){
11 domConst.place("<p>Requesting...</p>", "output");
12 request("./helloworld.json", {
13 handleAs: "custom"
14 }).then(function(data){
15 domConst.place("<p>data: <code>" + JSON.stringify(data) + "</code>", "output");
16 });
17 });
18 });
dojo/request的更多相关文章
- dojo/request模块整体架构解析
总体说明 做前端当然少不了ajax的使用,使用dojo的童鞋都知道dojo是基于模块化管理的前端框架,其中对ajax的处理位于dojo/request模块.一般情况下我们使用ajax请求只需要引入do ...
- dogo 官方翻译 Ajax with dojo/request
require(["dojo/request"], function(request){ request("helloworld.txt").then( fun ...
- 用 dojo/request/script 玩垮域
dojo/request/script 可以用于向服务器发送跨域请求,如JSONP等.但单看官方文档有点不容易理解,特将体会记录. require(["dojo/request/script ...
- Dojo初探之5:dojo的request(请求)操作、请求过程事件绑定和隐藏数据data()操作(基于dojo1.11.2版本)
前言: 上一章详细阐述了dojo的事件绑定操作,本章将讲解dojo的请求操作 注:dojo的请求操作与js和jquery完全不同! 1.dojo的请求 dojo通过request.get()/.put ...
- 现代DOJO(翻译)
http://dojotoolkit.org/documentation/tutorials/1.10/modern_dojo/index.html 你可能已经不用doio一段时间了,或者你一直想保持 ...
- 《静静的dojo》 总体教程介绍
web2.0时代,ajax技术成为整个前端开发领域的基石.大部分的书籍.博客由此切入来介绍前端类库与框架,所以dojo往往只被当做一个ajax类库来介绍,然而仅仅以此来定位dojo,无异于管中窥豹.对 ...
- dojo Provider(script、xhr、iframe)源码解析
总体结构 dojo/request/script.dojo/request/xhr.dojo/request/iframe这三者是dojo提供的provider.dojo将内部的所有provider构 ...
- require、module、exports dojo中的三个特殊模块标识
查看dojo源码过程中,发现这三个模块名并不以dojo.dijit.dojox开头,在dojo加载器中属于特殊模块名. require 这是一个上下文智能的加载器. 我们通过dojoConfig配置了 ...
- dojo 加载Json数据
1.今天研究了dojo datagrid加载WebService后台传上来的数据.研究来研究去发现他不是很难.用谷歌多调试一下就好了. 2.看很多例子,这个例子能够更好的帮我解决问题:https:// ...
随机推荐
- 读书时间《JavaScript高级程序设计》六:事件
Javascript与HTML之间的交互是通过事件实现的. 1. 事件流 事件流描述的是从页面中接收事件的顺序. <!DOCTYPE html> <html> <head ...
- WebStorm主题设置
对于使用WebStorm作为开发工具的筒子们.应该忍受不了默认的主题吧,可是自己去一个一个设置又太繁琐.So,去网上下个主题那是必须的. 搜来一圈,发现一个站点提供了不少主题.闲话少说,进入正题. 1 ...
- WebAPI 15 CORS
WebAPI 15 CORS 同源策略 首先基于安全的原因,浏览器是存在同源策略这个机制的,同源策略阻止从一个源加载的文档或脚本获取或设置另一个源加载的文档的属性. 对于同源必须要求URL在如下几个方 ...
- WINDOWS7,8和os x yosemite 10.10.1懒人版双系统安装教程
安装过程 磁盘划分 懒人版如果不是整盘单系统或者双硬盘双系统安装我们需要在当前系统磁盘划分两块磁盘空间,一个用来做安装盘,一个作为系统盘. 我这里是单硬盘,想从最后一个盘符压缩出80GB的空来安装黑苹 ...
- iOS多用连接、反向协议、安全
资源 WWDC-2013-Session-708 BlackHat-US-2014-"It Just (Net)works" Understanding Multipeer Con ...
- 使用shell/python获取hostname/fqdn释疑(转)
一直以来被Linux的hostname和fqdn(Fully Qualified Domain Name)困惑了好久,今天专门抽时间把它们的使用细节弄清了. 一.设置hostname/fqdn 在Li ...
- 提升Mac os x 10.10+xcode6.1之后,Cocoapods发生故障的解决方案
提升Mac OS X 10.10+Xcode 6.1之后.Cocoapods图书馆管理也依赖于相应升级.现在最新的Release版本号是 0.34.在之前的版本号.当数据库更新和管理,你会遇到一个错误 ...
- js 模块化的规范
The Module Pattern,模块模式,也译为模组模式,是一种通用的对代码进行模块化组织与定义的方式.这里所说的模块(Modules),是指实现某特定功能的一组方法和代码.许多现 ...
- Entity Framework笔记(二)
前几日学习了在VS2010Console项目中使用Entity Framework,并且使用Code First模式.通过编写Model类,来生成数据库对应的表.并且,往表中写入数据以及获取表中的所有 ...
- Windows下Jekyll安装
一直用Mac,换了新公司使用的电脑是windows,网上粗略的看了一下Jekyll的安装.简略的实现了一遍 首先安装Ruby Ruby安装文件下载地址 下载对应版本,我的电脑是64位的下载64位的版本 ...