如何使webEnumerator.moveNext等到executeQueryAsync查询执行

时间:2014-04-12 10:01:45

标签: javascript jquery sharepoint

我想在将控制权交还给webEnumerator.moveNext之前完成executeQueryAsync吗?

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");
}

现在发生的事情是,我对“循环1”发出两次警报然后警告“循环2”应该是这样的,

Loop 1
Loop 2
Loop 1
Loop 2

2 个答案:

答案 0 :(得分:1)

JavaScript I / O通常是非阻塞的。

context.executeQueryAsync立即返回,因此它不断迭代原始循环。它接受完成后的回调。

你想要的是同步它。允许的一个概念是Promises。既然你已经用jQuery标记了它,你可以使用它的实现(或者更好,像Bluebird承诺的那样强大)并执行类似的操作:

// 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
         });
    });
}

使用像Bluebird这样强大的承诺库可以更简单,它首先使用Promise#reduce支持这种迭代形式,但我不想添加另一个库。

上面的代码将按顺序运行,如果你想检查它什么时候完成 - 它会返回一个promise本身。所以你可以做onGetSubwebsSuccess(...).then(function(){ /* done here */ });

答案 1 :(得分:0)

由于可以使用以下语法使用单个查询请求网络媒体资源(Web.AllProperties):

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

不需要使用executeQueryAsync方法执行任何后续异步请求,以便为每个网站加载网络媒体资源。

以下示例演示如何从子网站加载Web属性并将其保存到websProps数组中:

(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
    }
  );
})();