JavaScript / promise,对sharepoint的多个异步调用

时间:2015-02-21 14:04:47

标签: javascript sharepoint promise

我在SharePoint中的应用中使用以下网站获取所有子网站:

var getW = getWebs($q)
    .then(function (results) {
        console.log(results); // Object with results from the first execute.         
    });

function getWebs($q) {

    var deferred = $q.defer();

    //App context etc..

    web = appContextSite.get_web();
    subWebs = web.getSubwebsForCurrentUser(null);

    context.load(subWebs, 'Include(Url, Created, Title, Lists)');
    context.executeQueryAsync(Function.createDelegate(this, function () {

        enumSubWebs = subWebs.getEnumerator();
        var arraySubWebs = [];
        var list = [];

        while (enumSubWebs.moveNext()) {

            var subWeb = enumSubWebs.get_current(),
            subWebUrl = subWeb.get_url();

            var _list = subWeb.get_lists().getByTitle('Custom List'); 

            list.push({
                'listItem': _list.getItemById(1),
                'webTitle': subWeb.get_title()
            });

            context.load(list[list.length - 1].listItem);

            promises.push(list);
        }

        context.executeQueryAsync(Function.createDelegate(this, function () {
            for (var i = 0; i < list.length; i++) {
                console.log(list[i].listItem.get_fieldValue()['Title']);
            }
           // Not sure what to put here, because the promise is returned to my .then above before it enters here.
        }));
        Q.allSettled(promises).then(function () {
            deferred.resolve(list);
        });
    }));
    return deferred.promise;
};

然后,我想从每个网站按ID(在&#39;自定义列表&#39;)中获取一个列表项。

我不知道我做错了什么,但是返回了网页(包括列表数组),但是listItem似乎没有被执行。我应该如何使用promise在最后一次executeQuery之后返回所有内容?

2 个答案:

答案 0 :(得分:1)

您正在使用deferred antipattern。每个表示结果的异步操作should get its own promise,只有这样才能正确组合它们。目前你有类似对象列表的数组,但它需要成为一组承诺才能与Q.allSettled一起使用。

实际上,您甚至不需要Q.allSettled,因为您不会同时触发多个查询,但只需要一个查询。

build a helper function for the promise创作:

 function load(context, objs, args) {
     if (!Array.isArray(objs))
         context.load(objs, args);
     else
         for (var i=0; i<objs.length; i++)
             context.load(objs[i], args[i]);
     var deferred = $q.defer();
     context.executeQueryAsync(function(sender, args) {
         deferred.resolve(objs); // sender, args don't seem to be helpful
     }, function(sender, args) {
         deferred.reject(args);
     });
     return deferred.promise;
}

现在您可以像这样使用它:

function getWebs($q) {
    //App context etc..
    var web = appContextSite.get_web();
    var subWebs = web.getSubwebsForCurrentUser(null);

    return load(context, subWebs, 'Include(Url, Created, Title, Lists)')
//  ^^^^^^
    .then(function(loadedSubWebs) {
        var enumSubWebs = loadedSubWebs.getEnumerator();
        var list = [],
            loadList = [];

        while (enumSubWebs.moveNext()) {
            var subWeb = enumSubWebs.get_current(),
                subWebUrl = subWeb.get_url();

            var obj = {
                listItem: subWeb.get_lists().getByTitle('Custom List').getItemById(1),
                webTitle: subWeb.get_title()
            };
            list.push(obj);
            loadList.push(obj.listItem);
        }
        return load(context, loadList).then(function(loadedList) {
//      ^^^^^^
            for (var i = 0; i < loadedList.length; i++) {
                console.log(loadedList[i].get_fieldValue().Title);
            }
            return list;
        });
    }, function(err) {
        // the load failed. `err` will be the `args` passed to `reject`
        console.log("list doesn't exist in this web");
        // you can still resolve the promise:
        return [];
        // or alternatively rethrow the exception:
        throw err;
    });
}

答案 1 :(得分:0)

这里的内容与Bergi的答案非常相似,但却是独立派生的。

主要区别在于我已将context.load()语句留在主例程中,并且只是context.executeQueryAsync()。这比Bergi的load()更不合理,但是更简单的帮助和更简单的主程序。

var getW = getWebs($q).then(function (results) {
    console.log(results); // log the `list` derived from the first execute.         
});

function executeQueryPromisified(context) {
    /* Ref 1 */
    var deferred = $q.defer();
    context.executeQueryAsync(
        function(sender, args) {
            deferred.resolve(args);
        },
        function(sender, args) {
            deferred.reject(args);
        }
    );
    return deferred.promise;
};

function getWebs($q) {
    var web = appContextSite.get_web(),
        subWebs = web.getSubwebsForCurrentUser(null);
    context.load(subWebs, 'Include(Url, Created, Title, Lists)');
    return executeQueryPromisified(context).then(function(args) {
        var enumSubWebs = subWebs.getEnumerator(),
            list = [], subWeb, obj;
        while (enumSubWebs.moveNext()) {
            subWeb = enumSubWebs.get_current();
            obj = {
                'listItem': subWeb.get_lists().getByTitle('Custom List').getItemById(1),
                'webTitle': subWeb.get_title()
            };
            list.push(obj);
            context.load(obj.listItem);
        }
        return executeQueryPromisified(context).then(function() {
            for (var i = 0; i < list.length; i++) {
                console.log(list[i].listItem.get_fieldValue()['Title']);
            }
            return list;
        });
    }).catch(function (args) {
        /* Ref 1 */
        console.error('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
    });
};

参考1:Sharepoint documentation; SP.ClientContext.executeQueryAsync method