How to make webEnumerator.moveNext wait until executeQueryAsync query executes

南笙酒味 提交于 2019-12-25 18:48:28

问题


I want executeQueryAsync to complete before giving back control to webEnumerator.moveNext, anyway ?

function onGetSubwebsSuccess(sender, args) {
    var webEnumerator = webCollection.getEnumerator();

    while (webEnumerator.moveNext()) {
        alert("Loop 1");
        web = webEnumerator.get_current();
        this.props = web.get_allProperties();
        context.load(this.props);
        context.executeQueryAsync(Function.createDelegate(this, gotProperty), Function.createDelegate(this, failedGettingProperty));
    }
}

function gotProperty() {
    var myPropBag = this.props;
    alert("Loop 2");
}

What's happening now is, I get alert for "Loop 1" twice and then alert for "Loop 2" when it should be like this,

Loop 1
Loop 2
Loop 1
Loop 2

回答1:


JavaScript I/O is usually non blocking.

context.executeQueryAsync returns immediately, so it keeps iterating the original loop. It accepts a callback for when it's done.

What you want is to synchronize it. One concept that allows that is Promises. Since you already tagged this with jQuery, you can use its implementation (or better, a strong one like Bluebird promises) and do something like:

// promisify executing the query in a context
function execute(context){
    var d = $.Deferred();
    context.executeQueryAsync(function(v){ return d.resolve(v)},
                              function(e){ return d.reject(v)});
    return d.promise();
}

function onGetSubwebsSuccess(sender, args) {
    var webEnumerator = webCollection.getEnumerator();
    return $.when(1).then(function iterate(){ // start an empty promise
         if(!webEnumerator.moveNext()) return ; // done iterating
         alert("Loop 1"); // console.log is better for this though
         var web = webEnumerator.get_current();
         var props = web.get_allProperties();
         context.load(this.props);
         return execute(context).then(function (result){
              alert("Loop 2");
              alert(result); // do whatever you want with the result of the query
              return iterate(); // loop
         });
    });
}

This can get a lot simpler using a stronger promise library like Bluebird which supports this form of iteration using Promise#reduce in the first place, but I didn't want to add another library.

The code above will run in sequence, if you want to check when it's done - it returns a promise itself. So you can do onGetSubwebsSuccess(...).then(function(){ /* done here */ });




回答2:


Since Web properties (Web.AllProperties) could be requested using a single query using the following syntax:

clientContext.load(webs,'Include(Url,AllProperties)');

there is no need to perform any subsequent asynchronous requests using executeQueryAsync method to load web properties per every web.

The following example demonstrates how to load web properties from sub webs and save them into websProps array:

(function(){
  var ctx = SP.ClientContext.get_current();
  var webs = ctx.get_web().get_webs();
  var websProps = {};
  ctx.load(webs,'Include(Url,AllProperties)');  //Note: Explicitly specify which properties to load for Web  
  ctx.executeQueryAsync(function(){
       var e = webs.getEnumerator();
       while (e.moveNext()) {
          var web = e.get_current();
          var webUrl = web.get_url();
          var props = web.get_allProperties();
          var propNameValues = props.get_fieldValues();
          //save properties  
          //Note: For demonstration purposes vti_defaultlanguage property is saved, change it to your property name
          websProps[webUrl] = {'DefaultLanguage': propNameValues['vti_defaultlanguage']};
       }
       console.log(JSON.stringify(websProps)); 
    },
    function(sender, args){
        //Handle error
    }
  );
})();


来源:https://stackoverflow.com/questions/23028886/how-to-make-webenumerator-movenext-wait-until-executequeryasync-query-executes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!