管中窥豹(1) Model.save
Liber 2013-10-22 09:52

前段时间,看到几篇关于各大前端开发框架的PK文章,还挺有意思:
JavaScript MVC框架PK:Angular、Backbone、CanJS与Ember
JavaScript宝座:七大框架论剑
对文章中的这句话颇有感触:
Jeremy好像进入了一种禅宗所谓的入定的状态,对一切都能坦然接受。他就像一个大人,看着一群孩子在那里辩论。
这是秒杀一切的节奏啊有没有?虽然我不是Backbone的狂热拥虿,但对于一个经常使用Backbone开发的人来说,心里还是有一些滋滋的得意的哈 :)

正好,最近在分析Backbone的源码,本着知识需要总结积累的原则,干脆就搞了一个管中窥豹的系列,希望通过对一些亮点的分析,启发大家对Backbone的探索欲,一起来窥探Backbone的精髓。

说明:
Backbone.js版本:Development Version (1.1.0)
开发者工具:Chrome

下面进入主题:

随着移动互联网以及富客户端的兴起,应该说,SPA(Single Page Application)开发,目前进入一个迅猛发展的趋势,而个人认为,SPA的一个很重要的原则就是:RESTful
所以,我们先来看看Model.save是怎么支持RESTful的:

Backbone的Model有一个url的参数,当我们调用save方法的时候,Backbone会根据这个地址,向服务端请求资源。所以,一般服务端那边,都会根据RESTful的原则提供好相应的服务。
所以,准确的说法,不是Backbone怎么支持RESTful,而是当服务端提供了RESTful的服务,Backbone能帮你非常方便实现请求。

接下来,我们看具体的代码,Model.save的代码在448行,在看到这里之前,我们先看一下265行:

  _.extend(Model.prototype, Events, {
    ...
    ...
    save: function(key, val, options) {
    }
    ...
    ...
  });

这样一看,大家就能更清楚的看到,save这个方法是如何成为Model的方法了吧。
然后,我们看到save的方法里面:

      var attrs, method, xhr, attributes = this.attributes;

      // Handle both `"key", value` and `{key: value}` -style arguments.
      if (key == null || typeof key === 'object') {
        attrs = key;
        options = val;
      } else {
        (attrs = {})[key] = val;
      }

看到这里的注释,它告诉我们,使用save传递参数的时候,可以这样:
someModel.save("name", "value", {wait: true}),也可以这样someModel.save({"name": "value"}, {wait: true})。这也是贯穿Backbone的一个原则,很多地方对hash参数的处理都是这样的,如Model.set
这让我想起了jQuery的CSS方法,不知道Backbone是不是受到了它的启发。
然后我的问题就出来了,如果是以后一种方式,那save方法的参数options,岂不就是undefined了吗?因为方法希望接收三个参数,而实际只传入了两个参数。
这倒也没什么,但可怕的地方就在454行options = val;,这里竟然敢这样使用options参数,这是要闹哪样啊?
我后来试着去查,这个options属性,到底赋给谁,我试了很多:

console.log(window.options);
console.log(someModel.options);
console.log(Backbone.options);

竟然全都是undefined,后来,我仔细查了一下arguments的相关知识,最后个人认为,这里的options应该还是在这个save方法的作用域中,就像是局部参数一样,值只在save方法里面可用。
希望今后有哪位大神能证实一下我的想法。

然后,还有一个很巧妙的地方:
save方法会根据{wait: true}来判断,在save之前,是执行Model.set还是Model._validate,如果validation失败了,则直接返回false,这对保持我们业务逻辑代码的连贯性实在是太好了。
如果validation成功了,就会发起一个异步的ajax请求,返回请求的xhr,注意,这里的xhr并不是要等到异步请求之后才有返回值,而是按代码执行顺序往下走,异步请求成功之后的逻辑在success方法里面,对save方法本身的执行顺序不造成影响。

这里面还有一些我不太明白的地方,如: 474行代码的含义;
469代码段处理的用意:this.attributes被临时赋值之后又没使用到,为什么要临时赋值呢?

save方法就先到这里了,欢迎大家直接联系我一起讨论。