Category: RIA Technology

JSONP enable you to send request to other domain beyond the same domain policy. And the corss domain alternative to AJAX.

JSONP is natively supported by JQuery, Zepto (alternative to JQuery for mobile usages). But When you require JSONP and DO NOT want to add the huge JQuery to your code base. This library will be useful.

var JSONP = (function () {
    var counter = 0,
        head, query, key, window = this;

    function load(url) {
        var script = document.createElement('script'),
        var done = false;
        script.src = url;
        script.async = true;

        script.onload = script.onreadystatechange = function () {
            if (!done && (!this.readyState || this.readyState === "loaded" || this.readyState === "complete")) {
                done = true;
                script.onload = script.onreadystatechange = null;
                if (script && script.parentNode) {
                    script.parentNode.removeChild(script);
                }
            }
        };
        if (!head) {
            head = document.getElementsByTagName('head')[0];
        }
        head.appendChild(script);
    }

    function jsonp(url, params, error, callback) {
        query = "?";
        params = params || {};
        for (key in params) {
            if (params.hasOwnProperty(key)) {
                query += encodeURIComponent(key) + "=" + encodeURIComponent(params[key]) + "&";
            }
        }
        var jsonp = "json" + (++counter);
        window[jsonp] = function (data) {
            callback(data);
            try {
                delete window[jsonp];
            } catch (e) {}
            window[jsonp] = null;
        };

        load(url + query + "callback=" + jsonp);

        error = error ||
        function () {};

        window.setTimeout(function () {
            if (typeof window[jsonp] == "function") {

                // replace success with null callback in case the request is just very latent.
                window[jsonp] = function (data) {
                    try {
                        delete window[jsonp];
                    } catch (e) {}
                    window[jsonp] = null;
                };

                // call the error callback
                error();

                // set a longer timeout to safely clean up the unused callback.
                window.setTimeout(function () {
                    if (typeof window[jsonp] == "function") {
                        try {
                            delete window[jsonp];
                        } catch (e) {}
                        window[jsonp] = null;
                    };
                }, 120000);
            };
        }, 10000);

        return jsonp;
    }
    return {
        get: jsonp
    };
}());

/*
Example:
----------------

var url = 'http://blog.eood.cn/api';
var error = function() {alert('error');};
var success = function(data) {
        // process the data
};
JSONP.get( url, {'parm1': 'parm1_value', 'parm2': 'parm2_value'}, error, success);

*/

客户端计算能力的增强,使 WEB 技术发展的天枰又开始偏向客户端运算。比如 Facebook 将模板渲染的运算放到了浏览器,浏览器先将模板下载到本地,再按需从服务器请求 JSON 格式的数据,然后在浏览器中渲染。对于提供给搜索引擎抓取的内容仍然可以在服务器端拼接完成后再输出。为了提高开发效率,可以考虑在服务器端也用 Javascript 或者其他语言拼接渲染 JSON 格式的数据和与客户端一致的模板。Mustache 就提供了这样的一种机制,并且支持大部分 WEB 语言。但是比较高效的服务器端方案仍然是用 Javascript 来写,用 NodeJS 向浏览器输出 JSON 数据和重用浏览器模板渲染代码向搜索引擎输出完整 HTML 数据。

NodeJS 和倍受推崇的 WEB 服务器 Nginx 类似,都采用 Event-driven 模型,对于单核服务器,只需要开一个进程就可以同时 serve 成千上万的客户。

不仅仅是 NodeJS, 对于 RIA 来说,支持最完善的仍然是 Javascript,基于 XUL 的客户端方案也需要 Javascript 作为开发语言,并且 Javascript 支持常见的高级特性比如 lambda,map-reduce 。

所以 Javascript 在服务器端和客户端都有很大的前景。设计模式既是解决问题的template,也是代码的组织方式。略去常见模式,仅仅涉及几个在 Javascript 中比较常用的模式:

用 prototype 的构建模式:

function Car(model, year, miles){
   this.model = model;
   this.year    = year;
   this.miles  = miles;
}

/*
 Note here that we are using Object.prototype.newMethod rather than
 Object.prototype so as to avoid redefining the prototype object
*/
Car.prototype.toString = function(){
		return this.model + " has done " + this.miles + " miles";
};

var civic = new Car("Honda Civic", 2009, 20000);
var mondeo = new Car("Ford Mondeo", 2010, 5000);

console.log(civic.toString());

单件模式:

var Singleton =(function(){
	var instantiated;
	function init (){
		/*singleton code here*/
		return {
			publicMethod:function(){
				console.log('hello world')
			},
			publicProperty:'test'
		}
	}

	return {
		getInstance :function(){
			if (!instantiated){
				instantiated = init();
			}
			return instantiated;
		}
	}
})()

/*calling public methods is then as easy as:*/
Singleton.getInstance.publicMethod();

可以传递参数的单件模式:

var SingletonTester = (function(){

  //args: an object containing arguments for the singleton
  function Singleton(args) {

   //set args variable to args passed or empty object if none provided.
    var args = args || {};
    //set the name parameter
    this.name = 'SingletonTester';
    //set the value of pointX
    this.pointX = args.pointX || 6; //get parameter from arguments or set default
    //set the value of pointY
    this.pointY = args.pointY || 10;  

  }

 //this is our instance holder
  var instance;

 //this is an emulation of static variables and methods
  var _static = {
    name: 'SingletonTester',
   //This is a method for getting an instance

   //It returns a singleton instance of a singleton object
    getInstance: function (args){
      if (instance === undefined) {
        instance = new Singleton(args);
      }
      return instance;
    }
  };
  return _static;
})();

var singletonTest = SingletonTester.getInstance({pointX: 5});
console.log(singletonTest.pointX); // outputs 5

模块模式:

var someModule = (function(){

  //private attributes
  var privateVar = 5;

  //private methods
  var privateMethod = function(){
  return 'Private Test';
  };

  return {
        //public attributes
        publicVar    : 10,
        //public methods
        publicMethod : function(){
        return ' Followed By Public Test ';
         }, 

         //let's access the private members
          getData : function(){
          return privateMethod() + this.publicMethod() + privateVar;
         }
       }
    })(); //the parens here cause the anonymous function to execute and return

someModule.getData();

观察者模式:

它适合pub-sub进行信息分发

function Observer(){
    this.functions = [];
}

Observer.prototype = {
    subscribe : function(fn) {
        this.functions.push(fn);
    },

    unsubscribe : function(fn) {
        this.functions = this.functions.filter(
            function(el) {
                if ( el !== fn ) {
                    return el;
                }
            }
        );
    },

    update : function(o, thisObj) {
        var scope = thisObj || window;
        this.functions.forEach(
            function(el) {
                el.call(scope, o);
            }
        );
    }
};
/*
    * Publishers are in charge of "publishing" eg: Creating the Event
    * They're also in charge of "notifying" (firing the event)
*/
var obs = new Observer;
obs.update('here is some test information');

/*
    * Subscribers basically... "subscribe" (or listen)
    * And once they've been "notified" their callback functions are invoked
*/
var fn = function() {
    // my callback stuff
};
obs.subscribe(fn);

/*
    * Unsubscribe if you no longer wish to be notified
*/
obs.unsubscribe(fn);

JQuery 中的遍历:

  $.each(function(){});
  $('.items').each(function(){});

更多有用资源

http://www.hunlock.com/blogs/Functional_Javascript

http://www.addyosmani.com/resources/essentialjsdesignpatterns/book/#designpatternsjavascript