异步的 js 接口实现思路——导火线模型

2011-07-01 by Dron

在一些组件里,某些接口的内部实现需要做成异步的,通常是等待数据或者是其他资源加载,一个简单的例子:flash 方案本地存贮模块的封装,js 接口要考虑 flash 资源加载的情况。

以本地存贮为例,我们通常会有 get,set,remove 三个接口,就像这样:

var store = {
    set: function(name, value){
        // TODO:
    },

    get: function(name){
        // TODO:
    },

    remove: function(name){
        // TODO:
    }
};

考虑到 flash 资源的加载情况,你可能会想到诸为 callback,onReady 等词汇,也见过一些童鞋的封装,对外都提供了类似这样的接口:

store.onReady(fn);

然而,用户在使用 set,get,remove 等接口的时候,只能放到 onReady 里了。我的建议:如果 callback 函数不需要处理额外情况的话(比如 ajax 的回调需要让用户知道请求后的反馈细节),那么这个过程尽量对用户透明,理想的情况就是让用户没感觉 flash 的存在。用户仍然可以在任意地方很随意地调用 set 等接口。

鉴于此,我设计了一个异步的接口模型,我把它戏称作导火线模型,具体的用法就像这样:

var store = {
    set: function(name, value){
        // TODO:
    }.bindAs(swfReady),

    get: function(name){
        // TODO:
    },

    remove: function(name){
        // TODO:
    }.bindAs(swfReady)
};

这样一来,set 和 remove 接口就直接被异步化了,而 get 这样的接口因为需要同步获得返回值,不能被异步化,另当别论,我目前还没想到好的方案处理,以后再尝试一下缓存策略:比如 set 时,把 value 保存到私有变量上,get 时直接从变量上拿等等(如果不 set,先 get,非得从本地存贮里取怎么办?好了,以后再想方案吧,这是同步接口,非本文探讨的话题)。

为什么起名叫导火线呢?请你想象一下上面这样设计后的代码实现,显然,bindAs(swfReady) 方法需要把用户在任意地方的 set,remove 操作,先有序地堆积起来,等到 swfReady 了,再按原先的顺序重新“播放”一遍。就是一串鞭炮一样,每一个爆竹是有顺序地缠在中芯导火线上的,当有火种点了导火线头,鞭炮就按导火线所导的顺序一个一个爆炸了。

一个很简单的想法,顺便写了一个 Demo,大家共同探讨一下。类似的模型已经在音乐盒上有了成熟的应用(音量设置、播放进度、列表数据加载各种)。