我正在尝试编写一个函数,该函数将富文本内容控件列表和单个字符串作为参数,并使用此字符串替换所有匹配内容控件的内容。
虽然这适用于较少量的内容控件,但它会因包含大量内容控件的文档而失败。我必须处理包含700多个内容控件和单个标题的文档。在这种情况下,代码只替换前66X CC,然后使用GeneralException中止。我认为这只是由于大量的内容控件。当我尝试为所有这些CC(GeneralException)注册绑定时,我遇到了类似的问题。但这是一个不同的主题。
我试图解决这个问题,通过限制每个.sync()的更改量并循环通过CC,根据需要执行尽可能多的循环。然而,由于office-js的异步性质,这并不容易。到目前为止,我对javascript-async-promise-programming不是很熟悉。但这就是我想出来的:
function replaceCCtextWithSingleString (CCtitleList, string) {
var maxPerBatch = 100;
/*
* A first .then() block is executed to get proxy objects for all selected CCs
*
* Then we would replace all the text-contents in one single .then() block. BUT:
* Word throws a GeneralException if you try to replace the text in more then 6XX CCs in one .then() block.
* In consequence we only process maxPerBatch CCs per .then() block
*/
Word.run(function (context) {
var CCcList = [];
// load CCs
for(var i = 0; i < CCtitleList.length; i++) {
CCcList.push(context.document.contentControls.getByTitle(CCtitleList[i]).load('id'));
}
return context.sync().then(function () { // synchronous
var CClist = [];
// aggregate list of CCs
for(var i = 0; i < CCcList.length; i++) {
if(CCcList[i].items.length == 0) {
throw 'Could not find CC with title "'+CCtitleList[j]+'"';
}
else {
CClist = CClist.concat(CCcList[i].items);
}
}
$('#status').html('Found '+CClist.length+' CCs matching the criteria. Started replacing...');
console.log('Found '+CClist.length+' CCs matching the criteria. Started replacing...');
// start replacing
return context.sync().then((function loop (replaceCounter, CClist) {
// asynchronous recoursive loop
for(var i = 0; replaceCounter < CClist.length && i < maxPerBatch; i++) { // loop in loop (i does only appear in condition)
// do this maxPerBatch times and then .sync() as long as there are still unreplaced CCs
CClist[replaceCounter].insertText(string, 'Replace');
replaceCounter++;
}
if(replaceCounter < CClist.length) return context.sync() // continue loop
.then(function () {
$('#status').html('...replaced the content of '+replaceCounter+' CCs...');
return loop(replaceCounter, numCCs);
});
else return context.sync() // end loop
.then(function () {
$('#status').html('Replaced the content of all CCs');
});
})(0, CClist));
});
}).catch(function (error) {
$('#status').html('<pre>Error: ' + JSON.stringify(error, null, 4) + '</pre>');
console.log('Error: ' + JSON.stringify(error, null, 4));
if (error instanceof OfficeExtension.Error) {
console.log('Debug info: ' + JSON.stringify(error.debugInfo, null, 4));
}
throw error;
});
}
然而......它不起作用。它取代了前100个CC,然后停止。没有失败,没有例外或任何事情。 return loop(replaceCounter, CClist);
刚刚执行,我不知道为什么。如果我尝试在调试器中进入这一行,它会把我扔到office-js代码中。
有什么建议吗?
修改
我根据Juan Balmori的建议更新了我的代码,它起到了魅力作用:
function replaceCCtextWithSingleString_v1_1 (CCtitleList, string) {
Word.run(function (context) {
var time1 = Date.now();
// load the title of all content controls
var CCc = context.document.contentControls.load('title');
return context.sync().then(function () { // synchronous
// extract CC titles
var documentCCtitleList = [];
for(var i = 0; i < CCc.items.length; i++) { documentCCtitleList.push(CCc.items[i].title); }
// check for missing titles and replace
for(var i = 0; i < CCtitleList.length; i++) {
var index = documentCCtitleList.indexOf(CCtitleList[i]);
if(index == -1) { // title is missing
throw 'Could not find CC with title "'+CCtitleList[i]+'"';
}
else { // replace
CCc.items[index].insertText(string, 'Replace');
}
}
$('#status').html('...replacing...');
return context.sync().then(function () {
var time2 = Date.now();
var tdiff = time2-time1;
$('#status').html('Successfully replaced all selected CCs in '+tdiff+' ms');
});
});
}).catch(function (error) {
$('#status').html('<pre>Error: ' + JSON.stringify(error, null, 4) + '</pre>');
console.log('Error: ' + JSON.stringify(error, null, 4));
if (error instanceof OfficeExtension.Error) {
console.log('Debug info: ' + JSON.stringify(error.debugInfo, null, 4));
}
});
}
完成仍需要13995毫秒,但至少它可行: - )
任何想法,是什么引起了GeneralException?
我发布了一个有关速度问题的新问题:What is the fastest way of replacing the text of many content controls via office-js?
答案 0 :(得分:1)
好问题..很久以前我做了一些性能测试,我能够在文档中更改超过10k的内容控件。 700你应该没问题。 不确定为什么你预先填写一个列表,这是不需要的,你实际上导航2次收集,这对perf不利。您可以在遍历集合时进行字符串比较!
以下是一个示例,我刚刚对700内容控制文档进行了快速测试,该文档带有假设标记&#34; test&#34;。
我能够 1.将他们的文本与你想要比较的文本进行比较(它是一个字符串) 2.如果条件为真,则更改值。
完成操作需要5134毫秒,这是代码。我认为这是完全可以接受的。
希望这有帮助!
function perfContentControls() {
var time1 = Date.now(); // lets see in how much time we complete the operation :)
var CCs =0
Word.run(function (context) {
var myCCs = context.document.body.contentControls.getByTag("test");
context.load(myCCs);
return context.sync()
.then(function () {
CCs = myCCs.items.length
for (var i = 0; i < CCs; i++) {
if (myCCs.items[i].text == "new text 3") // you can check the cc content and if needed replace it....
myCCs.items[i].insertText("new text 4", "replace");
}
return context.sync()
.then(function () {
var time2 = Date.now();
var diff = time2 - time1;
console.log("# of CCs:" + CCs + " time to change:" + diff + "ms");
})
})
.catch(function (er) {
console.log(er.message);
})
})
}
&#13;