来自 word-win32-16 的一般异常错误。00.js:19:150094)\n 在 yi

General Exception Error from word-win32-16.00.js:19:150094)\n at yi

我有 100 个左右的 Word Open XML(.xml,不是 .docx,另存为 "Word XML Document")存储在 SharePoint 上的文档(组件)。

我使用AJAX通过选择加载这些,如xml,1对多到一个数组中,我也在其中管理选择顺序.

一旦用户选择了 "components" 他们就可以将它们插入到 Word 中,插入是通过数组遍历完成的(可能有更好的方法来做到这一点 - 但现在它确实有效) ,

wordBuild 进行加载

function writeDocSync(){
  // run through nameXMLArray to find the right sequence
  var x = 0;
  var countXMLAdds = 0;
  //debugger;
  toggleWriteButton("disable");
  $('.progress-button').progressInitialize("Building Word");
  toggleProgressBar(true);
  // only run if we have data present
  if(nameXMLArray.length > 0){
    // increment through sequentially until we have all values
    while (countXMLAdds <= checkedList.length){
      // repeatedly traverse the array to get the next in sequence
      while (x < nameXMLArray.length){
        if (Number(nameXMLArray[x].position) === countXMLAdds && nameXMLArray[x].useStatus === true){
          progHold = countXMLAdds;
          wordBuild(nameXMLArray[x].xml, nameXMLArray[x].filename, countXMLAdds);
        }
        x++;
      }
      x=0;
      countXMLAdds ++;
    }
    document.getElementById("showCheck").className = "results";
    writeSelections("<b>You just built your proposal using<br/>the following components:</b><br/>");
    toggleWriteButton("enable");
  }
}

xxxxxxxxx

function wordBuild(xmlBody, nameDoc, progress){ 
  var aryLN = checkedList.length;
  var progPCT = (progress/aryLN)*100;
  progressMeter.progressSet(progPCT);
  Word.run(function (context) {
    var currentDoc = context.document; 
    var body = currentDoc.body;
    body.insertOoxml(xmlBody, Word.InsertLocation.end);
    body.insertBreak(Word.BreakType.page, Word.InsertLocation.end);
    return context.sync().then(function () {
      showNotification("Written " + nameDoc);
    });
  })
  .catch(function (error) {
    showNotification('Error: ' + nameDoc + ' :' + JSON.stringify(error));
    if (error instanceof OfficeExtension.Error) {
      showNotification('Debug info: ' + JSON.stringify(error.debugInfo));
    }
  });
}

所有文档将单独加载,所有文档将分批加载,例如 10 - 30 或更多。

当我加载整个集时出现问题(我有一个 "check all" 选项)。 有时在我得到异常之前会构建 50 个,有时是 60 个,很少超过 60 个,但偶尔我会遇到一个没有发生异常的间隙,然后它会在以后继续。

异常(对每个文件重复)是:

Debug info: {} Error: componentABC.xml :{"name":"OfficeExtension.Error","code":"GeneralException","message":"An internal error has occurred.","traceMessages":[],"debugInfo":{},"stack":"GeneralException: An internal error has occurred.\n at Anonymous function (https://customerportal.sharepoint.com/sites/components/Shared%20Documents/componentAssembler/Scripts/Office/1/word-win32-16.00.js:19:150094)\n at yi (https://customerportal.sharepoint.com/sites/components/Shared%20Documents/componentAssembler/Scripts/Office/1/word-win32-16.00.js:19:163912)\n at st (https://customerportal.sharepoint.com/sites/components/Shared%20Documents/componentAssembler/Scripts/Office/1/word-win32-16.00.js:19:163999)\n at d (https://customerportal.sharepoint.com/sites/components/Shared%20Documents/componentAssembler/Scripts/Office/1/word-win32-16.00.js:19:163819)\n at c (https://customerportal.sharepoint.com/sites/components/Shared%20Documents/componentAssembler/Scripts/Office/1/word-win32-16.00.js:19:162405)"}

对于可能导致此问题的任何帮助,我们将不胜感激。

哦,我还应该说,引发异常的文件不会插入到Word中。但在较小的批次中 - 它们可以正常工作。

Word.run() 是一个异步调用,您可以进行的并发 Word.run() 调用的数量是有限制的。由于您在 while 循环中执行 Word.run(),因此所有循环都会同时启动,并且 运行 同时启动。

有几种方法可以解决这个问题。

  1. 将所有内容放在一个 Word.run() 调用中。这会将所有内容放在一个巨大的批次中,避免多次往返调用 Word。

    if (nameXMLArray.length > 0 {
      Word.run(function(context) {
        //...
        while(...) {
          wordBuild(context, nameXMLArray[x].xml, nameXMLArray[x].filename, countXMLAdds);  
        //...
        }
        return context.sync();
      });
    }
    
    function wordBuild(context, xmlBoxy, nameDoc, progress) {
      //everything as it currently is, except without the Word.run and the context.sync
    }
    
  2. 将 wordBuild 实现为承诺,并使用 AngularJS 的 $q 服务来链接承诺,大致如下所示:

    function wordBuild(...) {
      var deferred = $q.defer();
      Word.run( function(context) {
        // current code
        return context.sync().then(function() {
          deferred.resolve();
        });
      });
      return deferred.promise;
    }
    
    //Somewhere else
    for (var x…)
    {
      promises.add(wordBuild);
    }
    $q.all(promises);
    

    https://docs.angularjs.org/api/ng/service/$q

    Angularjs $q.all

  3. 链接 wordBuild 调用自己,如下所示:

    var x = 0;
    var context;
    
    function (wordBuild() {
      if (x >= nameXMLArray.length)
        return;
      else {
        context.document.body.insertOoxml(ooxml, Word.InsertLocation.end);
        x++;
        return context.sync().then(wordBuild);
      }
    });
    
    Word.run(function (ctx) {
      context = ctx;
      return wordBuild();
    }
    

    这种方法很难维护,但它可以工作。

顺便说一句,原始代码中的进度表仅在调用 Word 开始时更新,而不是实际 returns。您可能希望将进度表更新代码移动到回调中。

我最终使用了 jQuery 延迟,我已经在使用 jQuery 树视图和复选框等,所以这是有道理的。

这是 Geoffrey 的建议和我自己的建议的结合!我不能说它是好的代码,只有这样才行得通。 (如果是好的代码,我会花更多的时间去理解!)

我 运行 批 49 xml 文档插入,在 51 处异步调用 "Word.run" 在测试中失败,并且在一个 Word.run 中插入 80 个左右的文档导致 Word 冻结,因此尽管未证明 1 Word.run 内有 49 个插入似乎是 10 个的良好入门! 49 件中的 50 个插入允许 2450 个插入,这超出了我认为需要的任何内容,并且可能会破坏 Word!

为了让 deferreds 和 sent 变量在作为异步 deferreds 启动后保持它们的值,我必须创建一个变量来传输新的 deferreds 和值,所以我可以使用 "bind" 命令。 作为 Word async returns context.sync() 我检查批次的计数,当批次完成时,我然后调用下一批次 - 在 context.sync()

一种递归调用,仍然是 Geoffrey 的建议和批处理的组合。这具有 50 个批次的 49 个文档部分的理论限制。到目前为止,这在所有测试中都有效。

进度表存在于它自己的定时调用中,但由于 JavaScript 代码优先于 UI 它确实会跳转。例如 120 个文档,它会相当快地跳到一半以下,然后过一会儿跳到几乎完成,然后完成(有效地快速连续百分比增加 3 跳,建议的各种技巧效果为零(forceRepaint() 是最新的实验!)。

        function startUILock(){
            // batch up in groups of 49 documents (51 and more were shown to fail, 49 gives manouvre room)
            toggleProgressBar(true);
            $('.progress-button').progressInitialize("Building Word");
            progressMeter.progressSet(1);   
            $.blockUI({message: "Building word..."});
            setTimeout(forceRepaint, 3000);
        }

        function forceRepaint(){
            var el = document.getElementById('progDiv');
            el.style.cssText += ';-webkit-transform:rotateZ(0deg)';
            el.offsetHeight;
            el.style.cssText += ';-webkit-transform:none';
        }

        function UIUnlock(insertedCount){
            debugger;
            var pct = (insertedCount/checkedList.length)*100
              //showNotification('Progress percent is: ' + pct);
            if (insertedCount !== checkedList.length ){  
              progressMeter.progressSet(pct);
              forceRepaint();
            } else {
            $.unblockUI();
            progressMeter.progressSet(100); 
            }
        }

        function writeDocDeffered(){
            insertedCounter = 0;
            var lastBatch = 0;
            var x = 49;
            var z = checkedList.length + 1;
            if(x > z){
                    x=z;
            }
            deferreds = buildDeferredBatch(x, lastBatch);
            $.when(deferreds).done(function () {    
                    return;
                })
                .fail(function () {
                   //showNotification('One of our promises failed');
                });
        }

        function buildDeferredBatch(batch, lastBatch) {
            // this ensures the variables remain as issued - allows use of "bind"
            var deferredsa = [];
                            var docSender = {
                                defr : $.Deferred(),                        
                                POSITION: batch,
                                LASTPOSITION: lastBatch,
                                runMe : function(){                                     
                                this.defr.resolve(writeDocBatchedDeferred(this.POSITION, this.LASTPOSITION, this.defr));
                                }
                            }
                            // small timeout might not be required
                            deferredsa.push(setTimeout(docSender.runMe.bind(docSender), 10));                                                               
            return deferredsa;
        }

        function writeDocBatchedDeferred(batch, lastBatch, defr){
            // write the batches using deferred and promises
            var x;
            var countXMLAdds = lastBatch; 
            x = 0;
            var fileName;
            debugger;   
            // only run if we have data present
            if(nameXMLArray.length > 0){
            var aryLN = checkedList.length;
            // increment through sequentially until we have all values  
                Word.run(function (context) {
                var currentDoc = context.document; 
                var body = currentDoc.body; 
                while (countXMLAdds <= batch){      
                    // repeatedly traverse the array to get the next in sequence
                    while (x < nameXMLArray.length){                
                        if (Number(nameXMLArray[x].position) === countXMLAdds && nameXMLArray[x].useStatus === true){  
                            fileName = nameXMLArray[x].filename;
                            body.insertOoxml(nameXMLArray[x].xml, Word.InsertLocation.end);
                            body.insertBreak(Word.BreakType.page, Word.InsertLocation.end);
                            insertedCounter = countXMLAdds;                     
                            var latest = insertedCounter;
                            var timerIt = {                                         
                                LATEST: latest,         
                                runMe : function(){ 
                                UIUnlock(this.LATEST);
                                }
                            }
                            setTimeout(timerIt.runMe.bind(timerIt),1000);                                   
                        }
                    x++;    
                    }
                    x=0;
                    countXMLAdds ++;
                }
                return context.sync().then(function () {                            
                    if(countXMLAdds = batch){
                        var lastBatch = batch + 1;
                        // set for next batch
                        var nextBatch = batch + 50;
                        var totalBatch = checkedList.length + 1;
                        // do not exceed the total batch
                        if(nextBatch > totalBatch){
                            nextBatch=totalBatch;
                        }
                        // any left to process keep going
                        if (nextBatch <= totalBatch && lastBatch < nextBatch){
                            deferreds =  deferreds.concat(buildDeferredBatch(nextBatch, lastBatch));                            
                        } 
                        // this batch done
                        defr.done();                
                    }
                });
                })
                .catch(function (error) {
                showNotification('Error: ' + nameXMLArray[x].filename + " " + JSON.stringify(error));
                if (error instanceof OfficeExtension.Error) {
                    showNotification('Debug info: ' + JSON.stringify(error.debugInfo));
                }
            }); 
                document.getElementById("showCheck").className = "results";
                writeSelections("<b>You just built your document using<br/>the following components:</b><br/>");
            }
            return defr.promise;
        }