环境: Mac 10.12.6,Word 2016 (16.11.1),@microsoft/office-js "^1.1.4“
我想知道在如何使用CustomXMLParts以最大限度地提高读/写性能方面是否有任何指南或最佳实践,或者是否有一种“理想的”方法来对XML部件中的数据进行建模,以达到相同的目的。
我正在编写一个外接程序,根据该外接程序,我需要将一些数据保存在可见文档之外,但在docx文件中。
例如,我正在存储一个发票列表(可能是100-200张发票),每个发票都有典型的结构化数据(名称、id、日期、工作项列表)和一个自由式注释部分,其中可以包含多达5-10 to的文本、说明等。
我接受这些发票,在Word doc中呈现其中的一些,然后在任务窗格中对来自其余部分的数据进行一些可视化分析--用户可以在其中将注释写入(并保存)到自定义XML部件(到他们正在查看的发票中)。
现在..。我有点困惑..。我不确定是否最好将每个发票作为单独的CustomXMLPart存储在文件中(例如,每个发票一个XML文件),或者是否最好将所有发票存储在一个大型CustomXMLPart中,或者是否有一个中间位置(例如,每个XML部分10张发票)。如前所述,用例正在读取所有发票,然后零星地更新10%-20%的发票中的数据。
现在,我在每个XML部件存储一张发票,当我加载我的加载项并进行批量读取以将所有内容输入内存时,每张发票大约需要250到500 my才能并行地读取它们(所以,250-500 my* 100-200发票)。然后,它需要更长的时间(2-3倍)。使用performance.now()进行测试,并使用挂钟定时进行验证。
这似乎是一段很长的时间,所以我不知道我是否做错了什么--或者这仅仅是打开和从这些文件中提取数据所需的时间?
// Sequential example - excluding error handling and type-safety
// Parallel equivalent is essentially a Promise.all with a .map
// Approx 50ms
let result = await this.xmlPartsHelper.getByNamespaceAsync(...);
for (const item of result.value) {
// Approx 150-200ms
result = await this.xmlPartsHelper.getByIdAsync(item.id);
// Approx 150-200ms
result = await this.xmlPartsHelper.getXmlAsync(result.value);
// Approx 5ms
const invoice = this.mapper.reverseMap(result.value);
invoices.push(invoice)
}我用承诺手动包装了Office-JS回调,但是我已经用异步/等待、然后/catch和office-js回调测试了这个示例,结果几乎是一样的。
public getByNamespaceAsync(namespace: string): Promise<Office.AsyncResult> {
return new Promise<Office.AsyncResult>((resolve, reject) => {
Office.context.document.customXmlParts.getByNamespaceAsync(namespace, (result: Office.AsyncResult) => {
return resolve(result);
});
});
}
public getByIdAsync(id: string): Promise<Office.AsyncResult> {
return new Promise<Office.AsyncResult>((resolve, reject) => {
Office.context.document.customXmlParts.getByIdAsync(id, (result: Office.AsyncResult) => {
return resolve(result);
});
});
}
public getXmlAsync(xmlPart: Office.CustomXmlPart): Promise<Office.AsyncResult> {
return new Promise<Office.AsyncResult>((resolve, reject) => {
xmlPart.getXmlAsync((result: Office.AsyncResult) => {
return resolve(result);
});
});
}更新
我不完全理解的谜题之一是CustomXMLNode --也许这会有所帮助。似乎有一些方法可以在CustomXMLPart (https://dev.office.com/reference/add-ins/shared/customxmlnode.customxmlnode)的节点中专门获取/设置数据--所以这可能是一个中间选项,我可以将所有发票放在一个CustomXMLPart中(这样我就可以只为一个CustomXMLPart被文件系统击中),然后我可以有选择地更新这个CustomXMLPart的各个部分(使用CustomXMLNode),这样我就不只是做一个完整的删除和重新保存了吗?
发布于 2018-04-15 20:20:05
很好地利用了承诺,我正在为非承诺的officejs函数做同样的包装。有了基于承诺的api,您现在可以利用Promise.all()执行并行操作。您可以同时启动所有操作并等待完成。这应该更快。
function getAllParts(ids) {
return Promise.all(ids.map(id => xmlPartsHelper.getByIdAsync(id)));
}
let namespaces = await this.xmlPartsHelper.getByNamespaceAsync(...);
getAllParts(namespaces.value).then((results) => {
console.log('invioces are', results);
});在文档中存储数据的另一种方法是Office.context.document.settings。您可以使用它作为密钥/值存储,并将JSON作为您的值。也许试着把你所有的发票放在一个数组中,然后把它写到同一个键上。下面是我的助手函数来完成这个任务:
/** Set a document property. Properties are specific to the document and the Addin-ID.
* @param {string} propertyName Name of the property.
* @param {string} value Value of the property.
* @returns {Promise} A promise without content.
*/
function setDocumentProperty(propertyName, value) {
return new Promise((resolve, reject) => {
if (Office.context.document.settings) {
Office.context.document.settings.set(propertyName, value);
Office.context.document.settings.saveAsync((asyncResult) => {
if (asyncResult.status === Office.AsyncResultStatus.Failed) {
reject(`[ExcelApi] Property '${propertyName}=${value}' could not be saved. Error: ${asyncResult.error.message}`);
} else {
resolve(`[ExcelApi] Property '${propertyName}=${value}' saved.`);
}
});
} else {
reject('[ExcelApi] document.settings is not ready.');
}
});
}
/** Get a document property.
* @param {string} propertyName Name of the property. Properties are specific to the document and the Addin-ID.
* @returns {Promise<object>} A promise that contains the property value.
*/
function getDocumentProperty(propertyName) {
return new Promise((resolve, reject) => {
if (Office.context.document.settings) {
const result = Office.context.document.settings.get(propertyName);
if (result === null) reject(`[ExcelApi] Property '${propertyName}' not found.`);
resolve(result);
} else {
reject('[ExcelApi] document.settings is not ready.');
}
});
}https://stackoverflow.com/questions/49764127
复制相似问题