【问题标题】:jQuery Deferred/Promises with multiple SharePoint CAML Queries具有多个 SharePoint CAML 查询的 jQuery 延迟/承诺
【发布时间】:2016-01-22 12:27:01
【问题描述】:

大家好,我有来自三个独立 SharePoint 列表的三个异步调用,每个查询都有一个返回对象和数组的成功回调。我希望在所有三个成功回调返回后执行另一个函数。我不知道如何让它与 jQuery deferreds 一起工作。我的代码如下。请帮助我了解如何使用延迟来实现上述目标。

function managementMain() {
    //From here I want to call the third function after executing 
      the managementQuery function.
      outPutObj = managementQuery();
    //Execute some third function with outPutObj:
    third function(outPutObj);
}
function managementQuery() {
    //CAML definition 1 here.
    clContext.executeQueryAsync(Function.createDelegate(this, function () { var soObj = onSOQuerySucceeded(); }), Function.createDelegate(this, this.onQueryFailed));
    //CAML definition 2 here.
    clContext.executeQueryAsync(Function.createDelegate(this, function () { var poObj = onPOQuerySucceeded(); }), Function.createDelegate(this, this.onQueryFailed));
   //CAML definition 3 here.
   clContext.executeQueryAsync(Function.createDelegate(this, function () { var salesRepNamesList = onSalesRepNamesQuerySucceeded(); }), Function.createDelegate(this, this.onQueryFailed));
   return {
       soObj: soObj,
       poObj: poObj,
       salesRepList: salesRepNamesList
   }
}
function onSOQuerySucceeded() {
     //Do something with the SharePoint List and return an object called soObj.
}
function onSalesRepNamesQuerySucceeded() {
     //Do something with the SharePoint List and return an array called salesRepNames.
}
function onPOQuerySucceeded() {
     //Do something with the SharePoint List and return an object called poObj.
}

我遇到的问题是 soObj、poObj 和 salesRepNamesList 可能不会按时返回 managementQuery 函数返回。因此,outPutObj 可能在执行第三个函数时定义不正确。请指教。谢谢。

【问题讨论】:

    标签: jquery sharepoint promise deferred caml


    【解决方案1】:

    首先,代码比它需要的要复杂:

    • 您可以清除Function.createDelegate(),它 (a) 不是标准的 javascript,(b) 没有必要,因为应用它的函数都没有使用 this。 Microsoft 有点顽皮,在他们的示例中包括 Function.createDelegate(),因为它似乎与使用 clientContext.executeQueryAsync() 密切相关,但事实并非如此。
    • 按照惯例,带有Async 后缀的方法应该返回一个promise,从而无需创建/解析您自己的Deferred。但是,Microsoft 再次有点调皮,clientContext.executeQueryAsync() 不 遵循惯例。

    其次,如果不先聚合提供数据的 Promise,就无法聚合异步派生的数据。如给定的那样,问题中的代码缺少任何承诺聚合。由于这是 jQuery,我们希望在代码中的某处看到 jQuery.when()。


    关于承诺,最简洁的方法总是在最低级别进行承诺——在这种情况下,为clientContext.executeQueryAsync() 编写一个可重用的适配器函数,它返回所需的承诺。这将大大简化更高级别的函数managementQuery()。

    这是承诺:

    clContext.executeQueryAsync_ = function() {
        return $.Deferred(function(dfrd) {
            clContext.executeQueryAsync(function(sender,args) {
                dfrd.resolve({'sender':sender, 'args':args});
            }, function(sender,args) {
                dfrd.reject({'sender':sender, 'args':args})
            });
        }).promise();
    };
    

    现在,managementQuery() 可以写成没有 Deferreds 和没有 Function.createDelegate(),如下所示:

    function managementQuery() {
        var query = clContext.executeQueryAsync_;  // If clContext.executeQueryAsync() returns a promise, then assign clContext.executeQueryAsync() instead.
        var promise1 = query(/* so params */);
        var promise2 = query(/* po params */);
        var promise3 = query(/* salesRep params */);
    
        // Now aggregate the three promises with $.when(), and chain .then() to handle the delivered data.
        return $.when(promise1, promise2, promise3)
        .then(function(soObj, poObj, salesRepObj) {
            // soObj, poObj and salesRepObj each have .sender and .args properties.
            // Now the required object can be created and returned 
            // to become the data delivered (in a promise) by managementQuery().
            return {
                'soObj': onSOQuerySucceeded(),
                'poObj': onPOQuerySucceeded(),
                'salesRepList': onSalesRepNamesQuerySucceeded()
            };
        });
    }
    

    而managementMain()可以写成如下:

    function managementMain() {
        return managementQuery()
        .then(someOtherFunction) // someOtherFunction will be automagically passed the object created/returned above.
        .fail(function(e) {
            // Any promise rejection in managementQuery() or someOtherFunction will end up here.
            console.log(e);
            this.onQueryFailed();
        });
    }
    

    【讨论】:

    • 您好 Roamer,非常感谢您对整个代码的详细解释和额外输入。真的很感激,因为我是新手。我将为我的下一个代码以这种方式实现它并提供反馈。这看起来比我一直在做的要整洁得多。谢谢!!
    【解决方案2】:

    您实际上将创建 3 个延迟对象,每个异步请求一个。完成异步请求后,您将在延迟对象上调用 .resolve 方法

    // query will return a promise
    outputPromise = query();
    
    // your third function needs to wait for the promise to resolve
    // to ensure the wait, you use the .then() method on the promise above
    outputPromise.then(function(outputObj) {
        thirdFunction(outputObj);
    });
    
    function query() {
        // Create deferred objects
        var deferred1 = $.Deferred();
        var deferred2 = $.Deferred();
    
        clContext.executeQueryAsync(Function.createDelegate(this, function () { 
            var soObj = onSOQuerySucceeded();
            deferred1.resolve(soObj);
        }), Function.createDelegate(this, function () {
            this.onQueryFailed();
            deferred1.reject();
        }));
    
        clContext.executeQueryAsync(Function.createDelegate(this, function () { 
            var poObj = onPOQuerySucceeded();
            deferred2.resolve(poObj);
        }), Function.createDelegate(this, function() {
            this.onQueryFailed();
            deferred2.reject();
        }));
    
        // we must wait for all async ops to finish. to do this, we use the $.when() method
        // the $.when() method returns a promise that is resolved with the return
        // values of each deferred that was passed in. the then takes a callback
        // function and will spread each resolved value over the callback function's arguments
        return $.when(deferred1, deferred2).then(function(soObj, poObj) {
           // create the output object in the format you specified
           return {
               soObj: soObj,
               poObj: poObj
           }
        });
    }
    

    jQ Deferred 文档在这里:https://api.jquery.com/category/deferred-object/,以防您需要查找一些东西

    作为旁注,我强烈建议使用另一个 Promise 库,例如 bluebird 或 Q,而不是 jQuery 的 deferreds。它们符合广泛接受的 Promise/A+ 规范和随后的 ES2015 Promise 规范。 jQ 3 将有一个符合 Promises/A+ 的 deferred,但 deferred 模式不在 ES2015 中,您应该使用其他库提供的 Promise 模式。

    【讨论】:

    • 您好,nerdondon,我已接受它作为正确答案。我目前没有足够的点来公开展示它。无论如何,非常感谢您提供的非常清晰的解释和所有资源。在使用各种延迟对象尝试了 2 天之后,现在我开始了解它是如何工作的。谢谢!
    • 嘿没问题。我很高兴它帮助了你
    猜你喜欢
    • 2015-03-27
    • 2023-03-21
    • 1970-01-01
    • 2015-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-02
    相关资源
    最近更新 更多