【问题标题】:Add sub-routine for Office.js Javascript Word add-in using asynchronous execution context使用异步执行上下文为 Office.js Javascript Word 加载项添加子例程
【发布时间】:2018-11-13 01:21:40
【问题描述】:

我在为 Word 开发 Office.js 插件方面取得了很大成功。插件的常见任务之一是搜索和替换,需要插件中的多个操作按钮使用。因此,我想创建一个将搜索和替换任务分开的函数,这样我就可以避免错误并使代码更加模块化。我一直在尝试使用 Office.js 异步执行模型来执行此操作。

此代码有效(作为 React 类的方法):

    replaceX() {
    console.log("replaceX");
    window.Word.run(async (context: any) => {

        const range = context.document.getSelection();

        await context.sync();
        var query = "X";
        var replacement = "gabagool";

        var results = range.search(query);
        results.load();               

        await context.sync();

        for (var i=0; i<results.items.length; i++) {
            results.items[i].insertText(replacement,'Replace');
        }

        await context.sync();
    });
}

但是这段代码失败了:

    replaceX() {
    console.log("replaceX");
    window.Word.run(async (context: any) => {

        const range = context.document.getSelection();

        await context.sync();
        var query = "X";
        var replacement = "gabagool";

        this.replaceInRange(context, range, query, replacement, {});

        await context.sync();
    });
}

async replaceInRange(context:any, range:any, query:String, replacement:String, searchOptions:any) {
    console.log('replaceInRange');
    var results = range.search(query, searchOptions);
    results.load();
    await context.sync();

    for (var i=0; i<results.items.length; i++) {
        results.items[i].insertText(replacement,'Replace');
    }

}

我尝试了一些变体,但我确定我缺少一些基本的东西。谁能帮我找出正确的方法来处理需要访问父函数上下文的子例程?

【问题讨论】:

    标签: javascript reactjs typescript asynchronous office-js


    【解决方案1】:

    您的代码破坏了 Promise 链。您的replaceInRange 方法在其中有一个对context.sync 的异步调用,但replaceInRange 本身并没有等待,因此一旦它开始执行,执行引擎就会转到replaceInRange 调用下方的行,这是另一个context.sync。但最后一个context.sync 将完成,然后Word.run 将在字符串替换代码运行之前完成。

    尝试在调用 replaceInRange 之前添加一个 await 关键字,如下所示:

    await this.replaceInRange(context, range, query, replacement, {});
    

    我注意到的其他几件事:

    1. 不需要Word.run 中的第一个context.sync

    2. 您没有将任何参数传递给load() 方法。执行此操作时,将加载所有标量属性。这是不必要的性能损失。您只需加载text 属性即可执行insertText。使用results.load('text');

    3. Word.run 本身是异步的,所以你应该在调用它时使用await 关键字。您可以在没有await 的情况下逃脱,因为您的父方法在 Word.run 执行后什么都不调用,但是如果您修改了该方法以便在Word.run 之后调用更多的东西,那么更多的东西会在 @ 之前开始执行如果您不等待Word.run,则 987654342@ 已完成。

    有一本关于 Office 加载项的好书,其中包含有关这些主题的大量信息,包括 Promise 链:Building Office Add-ins。它花费了一些东西,但它是值得的。在你问之前,这不是我的书,我没有从它的销售中获得任何收益。

    【讨论】:

    • 谢谢,我会考虑买那本书——它看起来确实不错。我尝试添加 await 关键字并进行您建议的其他更改,以及添加更多日志记录语句。函数的其余部分实际上似乎根本没有执行,无论是否在 replaceinrange 之前有await。实际上,我添加了一个像这样的虚拟方法: dummy() { console.log('running dummy');即使我在 replaceInRange 函数之前运行它,该函数也不会记录任何内容。这非常令人困惑。
    • @Quinten 当我将 await 放在 replaceInRange 调用前面时,您的代码对我有用(并从前面删除了“this”)。我推测您如何调用 replaceX() 和/或如何使用“this”关键字会导致您出现问题,但我看不到足够的代码上下文来更准确。
    • 将其作为类的方法删除并使其成为独立的函数……对我来说已经足够了。非常感谢你的帮助。我将不得不阅读更多关于此的内容,因为这是我第一次涉足异步领域。
    • @Quinten,我建议的另一件事是确保您返回 Word.run 承诺或等待它 - 并确保在它上游的某个地方,您正在使用 @ 987654347@(如果使用await)或正在做.catch(基于承诺)。我发现从一开始就进行适当的错误处理需要对正在发生的事情进行大量猜测(当然,只有当你正确链接/等待承诺并且没有破坏承诺链 - 否则你仍然可以获得令人发指的无声错误)。
    猜你喜欢
    • 1970-01-01
    • 2017-02-27
    • 1970-01-01
    • 1970-01-01
    • 2011-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多