SJo*_*shi 5 ms-word officedev office-addins office-js
环境:Mac 10.12.6,Word 2016(16.11.1),@ microsoft/office-js"^ 1.1.4"
我想知道在如何使用CustomXMLParts方面有任何指导方针或最佳实践,以便最大限度地提高读/写性能,或者是否有一种"理想"方式来为同一目的在XML部件中建模数据.
我正在编写一个加载项,我需要在可见文档之外保留一些数据,但是在docx文件中.
例如,我存储了一张发票清单(可能是100-200张发票),每张发票都有典型的结构化数据(名称,ID,日期,工作项列表)和自由式备注部分,最多可包含5个-10kb的文字,说明等
我拿这些发票,在Word文档中渲染其中一些,然后在任务窗格中对其余数据进行一些可视化分析 - 用户可以将注释写入(并保存)回自定义XML部件(到该发票中)他们正在看).
现在......这里我有点困惑......我不确定将每张发票作为单独的CustomXMLPart存储在文件中是否更好(例如每张发票1个XML文件),或者是否最好存储所有发票在单个大型CustomXMLPart中,或者如果存在中间地点(例如,每个XML部分有10个发票).如上所述,用例是回读所有发票,然后偶尔更新10-20%的发票中的数据.
现在,我正在为每个XML部分存储1个发票,当我加载我的插件并进行批量读取以将所有内容都存入内存时,每个发票需要250-500平方英寸才能将它们并行读取(所以,250-500ms*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)
}
Run Code Online (Sandbox Code Playgroud)
我使用Promises手动包装Office-JS回调,但我已经使用async/await,然后是/ 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);
});
});
}
Run Code Online (Sandbox Code Playgroud)
UPDATE
我不完全理解的一个难题是CustomXMLNode - 也许这可能会有所帮助.似乎有一些方法专门在CustomXMLPart(https://dev.office.com/reference/add-ins/shared/customxmlnode.customxmlnode)的节点中获取/设置数据- 所以也许这就是中间选项,我可以把我的所有发票放到一个CustomXMLPart中(这样我只能为单个CustomXMLPart命中文件系统),然后我可以有选择地更新那个CustomXMLPart的部分(使用CustomXMLNode),这样我就不会这样做了完全删除并重新保存?
很好地使用了 Promise,我正在对非 Promise officejs 功能进行相同的包装。通过基于 Promise 的 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);
});
Run Code Online (Sandbox Code Playgroud)
在文档中存储数据的其他一些方法是 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.');
}
});
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
406 次 |
| 最近记录: |