This article has been first published on the infoq Chinese site. All Rights Reserved. The original Article is "using dojo to implement Ajax requests: xhr, cross-domain, and others". If you need to reprint it, please attach this statement. Thank you.
Infoq Chinese site is an online independent community for mid-and high-end technical personnel ,. net, Ruby, SOA, agility, architecture and other fields to provide timely and in-depth information, high-end technology conferences such as qcon, offline technology exchange activities qclub, free mini book download such as architect, etc..
Easily implementing Ajax requests in any browser is the original intention of every Ajax framework. Dojo undoubtedly provides a wealth of support in this regard. In addition to XMLHttpRequest, dynamic scripts, IFRAME, and RPC are also available, and the interfaces are unified and easy to use. In most cases, you only need one sentence to achieve the goal, saving you from the trouble of repeating the wheel. In addition, the conceptual integrity that dojo has always pursued is also embodied here. In other words, it is easier to have a feeling of being in the context of the Ajax Tool of dojo, because the API mode is unified, and some concepts involved here (such as deferred objects) also run through the entire dojo.
Xhr functions of dojo
The XMLHttpRequest function of dojo is called dojo. xhr. In addition to naming yourself dollar signs, it seems to be the most direct method. It is defined in the basic dojo library, so it can be used without additional require. It can implement any HTTP requests in the same domain. However, the more common ones are dojo. xhrget and dojo. xhrpost, which are simple encapsulation of the dojo. xhr function. Of course, according to the REST style, there are also dojo. xhrput and dojo. xhrdelete.
The parameters of these functions are uniform. Except for dojo. the first parameter of xhr is all the dojo. all xhr * series functions accept the same hash parameter, which contains the request details, for example, URL, synchronization, content to be sent to the server (can be a common object, form, or plain text), timeout setting, and type of returned results (very rich and scalable) and callback when the request is successful or fails. All dojo. the return values of the xhr * function (in fact all Io functions) are the same. They are all deferred objects. As the name suggests, xhr * function can "delay" some things and make APIs more flexible.
The following two examples may bring you some intuitive feelings:
Dojo. xhrget ({URL: "something.html", load: function (response, ioargs) {// use response to do something on the console. log ("xhr get success:", response); return response; // response must be returned}, error: function (response, ioargs) {console. log ("xhr get failed:", response); return response; // response must be returned }}); // The deferred object allows synchronous calling to write var deferredresult = dojo. xhrpost ({URL: "something.html", form: formnode, // dojo will automatically convert form into object Timeout: 3000, // dojo will ensure the validity of the timeout setting handleas: "JSON" // The response will be considered as JSON and automatically converted to object}); // call the callback function deferredresult when the response result is available. then (function (response) {console. log ("xhr get success:", response); return response; // response must be returned });
First, explain timeout. Except IE8, most XMLHttpRequest objects do not have the built-in timeout function. Therefore, setTimeout must be used. When there are a large number of requests at the same time, you need to set a separate timer for each request, which may cause serious performance problems in some browsers (mainly IE. Dojo only uses a single setinterval to regularly round the status of all the uncompleted requests (with an interval of 50 ms), so that all remote requests (including jsonp and IFRAME) are efficiently handled).
It is worth mentioning that the handleas parameter can be set to automatically identify the server's response content format and convert it to an object or text format for ease of use. According to the document, it accepts the following values: Text (default), JSON, JSON-comment-optional, JSON-comment-filtered, JavaScript, and XML.
And it is scalable. In fact, handleas only tells the xhr function to call the format conversion plug-in, that is, a method in the dojo. contenthandlers object. For example, dojo. contenthandlers. JSON is a plugin for processing JSON format. You can easily customize the format conversion plug-ins you need. Of course, you can also modify the behavior of the existing plug-ins:
Dojo. contenthandlers. JSON = (function (old) {return function (xhr) {var JSON = old (xhr); If (JSON. somesignalformserver) {dosomthing (JSON); Delete JSON. somesignalformserver;} return JSON ;}) (Dojo. contenthandlers. JSON); // a small trick to obtain the original method by passing Parameters
For details about each parameter, see the dojo documentation.
Virtual parameter classes
Here, I would like to mention the two features of dojo in API design. One is the concept of virtual parameter "class": By using JavaScript objects to flexibly expand features, a hash parameter is forcibly specified to belong to a "class ". For example, the parameters accepted by the dojo. xhr * series functions are called dojo. _ xhrargs. This "class" does not exist in actual code (do not try to use instanceof to verify it). It only stays on the concept and is more abstract than the abstract class, therefore, it is prefixed with a double underline (dojo is used to adding a single underline prefix to an abstract class ). This seems meaningless, but it actually simplifies the API, because it makes the association between APIs easier to remember and make it easier to use. This is more obvious when "Inheriting" this type. For example, dojo. _ xhrargs inherits from dojo. _ ioargs, which is a set of parameters that all Io functions must support. It also inherits from dojo. _ ioargs also includes dojo. io. script. _ ioargs and dojo. io. IFRAME. _ ioargs is used for dynamic script requests and IFRAME requests respectively. Subclass only adds a small number of attributes to the parent class, so that a large number of parameters have a tree structure. Originally, hash parameters replaced the fixed parameter order with precise parameter names. In addition to increasing flexibility and scalability, they actually increase the amount of memory (after all, parameter names cannot be spelled incorrectly ), this makes the API not as easy to use as it looks, and relieves this problem with the design of parameter classes.
This type of parameter classes can be seen everywhere in Dojo. If you read the source code, you will find that they are all declared in a special comment format in the form of normal code, like this:
/*=====dojo.declare("dojo.__XhrArgs", dojo.__IoArgs, { constructor: function(){ //summary: //... //handleAs: //... //...... } }); =====*/
This format can be automatically extracted into documents by the jsdoc tool. In this document, these virtualized classes are as dirty as the real classes.
Deferred object
Another API design feature is the widespread use of deferred objects. The deferred in Dojo is slightly improved based on mochikit, which is inspired by the concept of the same name in the python event-driven network toolkit twisted. In summary, the purpose of this object is to separate the declared position of the callback function in asynchronous IO from the called position so that, in the end of an asynchronous Io, developers can simply say "the goods have arrived and they want to use them", instead of specifying which callback functions should be called. The advantage of doing so is to make asynchronous Io write the same as synchronous io (data processing is always outside the data function, rather than inside), thus simplifying asynchronous programming.
Specifically, the asynchronous function always returns a proxy object synchronously (this is the deferred object), which can be seen as the representative of the data you want. It provides some methods to add a callback function, when data is available, these callback functions (which can be divided into multiple ones) are executed in order of addition. If an error occurs during the data retrieval process, the provided error processing function (there may be many) will be called. If you want to cancel this asynchronous request, you can also use the Cancel Method of the deferred object.
The core method of dojo. Deferred is as follows:
Then (callback, errback); // Add the callback function callback (result); // It indicates that the asynchronous call is successful and the callback function errback (error) is triggered ); // indicates that an error is generated in an asynchronous call and the cancel () function is triggered. // cancel an asynchronous call
Dojo also provides a when method to write synchronous values in the same way as Asynchronous deferred objects. For example:
// Implement var OBJ = {getitem: function () {If (this. ITEM) {return this. item; // return data synchronously here} else {return dojo. xhrget ({// here the returned deferred object URL: "togetitem.html", load: dojo. hitch (this, function (response) {This. item = response; return response;}) ;}}; // user code dojo. when (obj. getitem (), function (item) {// whether synchronous or asynchronous, The getitem function is used in the same way });
With the help of function closures, it is easier to create and use deferred objects. You can easily write a function for creating deferred objects and perform asynchronous tasks in synchronous writing. For example, write a function that uses store to obtain data:
VaR store = new dojo. data. queryreadstore ({...}); function getdata (START, count) {var d = new dojo. deferred (); // initialize a deferred object store. fetch ({start: Start, Count: Count, oncomplete: function (items) {// directly use the deferred object d in the upper closure. callback (items) ;}}); Return D; // return it as a result}
Cross-origin with dojo. Io. Script
Dojo. xhr * is only the encapsulation of the XMLHTTPRequest object. Due to the same-origin policy restrictions, it cannot send cross-origin requests. It must be dynamically created for cross-origin requests.