jQuery Deferred/Promises 具有多个 SharePoint CAML 查询

jQuery Deferred/Promises with multiple SharePoint CAML Queries

大家好,我从三个单独的 SharePoint 列表进行了三个异步调用,每个查询都有一个成功回调 return 对象和数组。我希望在所有三个成功回调 return 之后执行另一个函数。我不确定如何让它与 jQuery deferreds 一起使用。我的代码如下。请帮助我了解如何使用 deferreds 来实现上面的 objective。

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 到时候可能 returned 管理查询函数 returns。因此,到执行第三个函数时,outPutObj 可能定义错误。请指教。谢谢

您基本上会创建 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+ 兼容的延迟模式,但延迟模式不在 ES2015 中,你应该使用其他库提供的 Promise 模式。

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

  • 您可以清除 Function.createDelegate(),它 (a) 不是标准的 javascript,(b) 没有必要,因为 none 应用它的函数使用 this.微软有点顽皮,在他们的示例中包括 Function.createDelegate(),因为它似乎与使用 clientContext.executeQueryAsync() 密切相关,但事实并非如此。
  • 按照惯例,带有 Async 后缀的方法 应该 return 一个承诺,使您自己的 Deferreds 的 creation/resoltion 变得不必要。但是,Microsoft 又有点顽皮了,因为 clientContext.executeQueryAsync() 没有 遵循惯例。

其次,如果不首先聚合提供数据的承诺,则无法聚合异步派生的数据。如前所述,问题中的代码没有任何承诺的聚合。由于这是 jQuery,我们希望在代码中的某处看到 jQuery.when()


关于 promisification,最巧妙的方法始终是在最低级别进行 promisify - 在本例中为 clientContext.executeQueryAsync() 编写可重用的适配器函数,这 return 是所需的 promise。这将大大简化更高级别的功能 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();
    });
}