使用Jscex增强SharePoint 2010 JavaScript Client Object Model (JSOM)

SharePoint 2010提供了JSOM,来让我们可以直接在页面上通过JavaScript代码与SharePoint系统直接进行交互。在Web 2.0已经日益普及的今天,JavaScript在Web开发中越来越重要,所以JSOM对于SharePoint程序员来说,是一个非常好用的利器。

SharePoint 2010 JSOM对于服务器端的请求都是采用的异步方式。如果你使用过JSOM,那么对它的异步调用方式应该很熟悉了。SP.ClientContext对象有一个executeQueryAsync()方法,JSOM都是通过调用它来完成最终的服务器端请求,这个方法有2个参数,分别是成功后的回调函数和失败后的回调函数:

var ctx = SP.ClientContext.get_current();
// ...
ctx.executeQueryAsync(function() {
    // 服务器端请求成功完成
}, function() {
    // 服务器端请求失败
});

其实这种回调函数的方式,在JavaScript中算得上是最常见的一种异步代码风格。但这种风格的问题是,一旦代码的逻辑需要我们将多个异步方法“串接”起来,那么我们的JavaScript代码就会变成回调套回调,无论是编写还是阅读,都变得困难起来。

现在很多JavaScript库都开始使用Promises模型来简化异步模型,包括jQuery中新增的Deferred特性,其实都是Promises模型的一种实现。Windows 8中的WinJS默认也采用了Promises风格。但Promises模型实际上并没有彻底改变对回调函数的依赖。

嗯,说了这么多,当当当,浓重介绍JscexJeffery Zhao同志精心打造的用来简化JavaScript异步代码开发的一个扩展。Jscex用一种精巧的方式,在JavaScript中实现了类似.NET 4.0 TPL的异步模型。下面,我们来看看如何使用Jscex来增强SharePoint 2010 JSOM。

我选择对JSOM的扩展方式,是为SP.ClientContext添加一个方法,作为对内置executeQueryAsync()方法的替代。我们就使用executeAsync()作为新方法的名称吧。

SP.ClientContext.prototype.executeAsync = function () {
    var that = this;
    return Jscex.Async.Task.create(function (t) {
        that.executeQueryAsync(function () {
            t.complete('success');
        }, function () {
            t.complete('failure');
        });
    });
};

在为SP.ClientContext对象扩展了这个新的executeAsync()方法之后,我们就可以使用它来替代原有的executeQueryAsync()了。

我们以上一篇博客《使用JSOM创建一个SharePoint网站计数器》为例,来改造webHitCounter.js中的几个函数。

首先是getWebHitCountAsync()函数,这是这个函数之前的写法(使用了jQuery中的Deferred特性进行了封装)如下所示:

function getWebHitCountAsync() {
    return $.Deferred(function (dtd) {
        var ctx = SP.ClientContext.get_current();
        var web = ctx.get_web();
        var webProps = web.get_allProperties();
        ctx.load(webProps);
        ctx.executeQueryAsync(function () {
            var hitCount = webProps.get_fieldValues()['webHitCount'];
            if (!hitCount) {
                hitCount = 0;
            }
            dtd.resolve(hitCount);
        }, function () {
            dtd.reject(0);
        });
    }).promise();
}

这是使用Jscex对其进行了改造之后的写法:

var getWebHitCountAsync = eval(Jscex.compile('async', function () {
    var ctx = SP.ClientContext.get_current();
    var web = ctx.get_web();
    var webProps = web.get_allProperties();
    ctx.load(webProps);
    $await(ctx.executeAsync());
    var hitCount = webProps.get_fieldValues()['webHitCount'];
    if (!hitCount) {
        hitCount = 0;
    }
    return hitCount;
}));

是不是清晰多了呢?函数体内,完全没有了回调函数。

接下来是increaseWebHitCountAsync()函数。由于这个函数首先需要调用getWebHitCountAsync()函数来得到当前网站计数器值,然后给这个值加一,然后再异步更新回SharePoint服务器,所以之前的代码就不得不“回调套回调”了:

function increaseWebHitCountAsync() {
    return $.Deferred(function (dtd) {
        getWebHitCountAsync().done(function (hitCount) {
            var ctx = SP.ClientContext.get_current();
            var web = ctx.get_web();
            var webProps = web.get_allProperties();
            webProps.set_item('webHitCount', ++hitCount);
            web.update();
            ctx.executeQueryAsync(function () {
                dtd.resolve();
            }, function () {
                dtd.reject();
            });
        });        
    }).promise();
}

换成使用Jscex之后:

var increaseWebHitCountAsync = eval(Jscex.compile('async', function () {
    var hitCount = $await(getWebHitCountAsync());
    var ctx = SP.ClientContext.get_current();
    var web = ctx.get_web();
    var webProps = web.get_allProperties();
    webProps.set_item('webHitCount', ++hitCount);
    web.update();
    $await(ctx.executeAsync());
}));

不得不说,代码比之前的版本好看多了。

我不想把本文变成一篇介绍Jscex的文章,你可以访问Jscex在github上的主页:https://github.com/JeffreyZhao/jscex,来详细了解Jscex的用法。

posted on 2012-04-13 00:20  kaneboy  阅读(1482)  评论(2编辑  收藏  举报

导航