客户端 JavaScript 从服务器端文档集和获取函数接收过时的值
Client JavaScript receiving outdated values from server-side document set and fetch functions
我为文档编写了一个Google Apps脚本,用于重复设置段落的文本,然后检索它。如果我在脚本文件中执行此操作,一切正常(请参阅下面的函数"test"):
Code.gs:
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
function test() {
DocumentApp.getActiveDocument().getBody().insertParagraph(0, "");
for(var i = 0; i < 10; i++) {
Logger.log("Inserting " + i);
setText(i);
Logger.log("Received " + getText());
}
}
function setText(text) {
var paragraph = DocumentApp.getActiveDocument().getBody().getChild(0).asParagraph();
paragraph.clear();
paragraph.setText(text);
}
function getText() {
var paragraph = DocumentApp.getActiveDocument().getBody().getChild(0).asParagraph();
return paragraph.getText();
}
function onOpen() {
test();
DocumentApp.getUi()
.createMenu('Test')
.addItem('Open', 'openTest')
.addToUi();
}
function openTest() {
var html = HtmlService
.createTemplateFromFile('index')
.evaluate()
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
DocumentApp.getUi().showSidebar(html);
}
即测试函数的行为符合预期:
[16-03-02 06:06:58:652 PST] Inserting 0
[16-03-02 06:06:58:657 PST] Received 0
[16-03-02 06:06:58:658 PST] Inserting 1
[16-03-02 06:06:58:663 PST] Received 1
[16-03-02 06:06:58:664 PST] Inserting 2
[16-03-02 06:06:58:670 PST] Received 2
[16-03-02 06:06:58:670 PST] Inserting 3
[16-03-02 06:06:58:676 PST] Received 3
[16-03-02 06:06:58:677 PST] Inserting 4
[16-03-02 06:06:58:683 PST] Received 4
[16-03-02 06:06:58:684 PST] Inserting 5
[16-03-02 06:06:58:690 PST] Received 5
[16-03-02 06:06:58:690 PST] Inserting 6
[16-03-02 06:06:58:696 PST] Received 6
[16-03-02 06:06:58:697 PST] Inserting 7
[16-03-02 06:06:58:703 PST] Received 7
[16-03-02 06:06:58:703 PST] Inserting 8
[16-03-02 06:06:58:708 PST] Received 8
[16-03-02 06:06:58:709 PST] Inserting 9
[16-03-02 06:06:58:715 PST] Received 9
但是,如果我做同样的事情但从 HTML 页面:
JavaScript:
<script>
var i = 0;
$(document).ready(insert);
function log(msg) {
$('#log').append('<div></div>').append(document.createTextNode(msg));
}
function insert() {
log("Inserting " + i);
google.script.run.withSuccessHandler(receive).setText(i);
}
function receive() {
google.script.run.withSuccessHandler(function(text) {
log("Received " + text);
i++;
if(i < 10)
insert();
}).getText();
}
</script>
我得到的结果是这样的
Inserting 0
Received
Inserting 1
Received 1
Inserting 2
Received 2
Inserting 3
Received 3
Inserting 4
Received 3
Inserting 5
Received 5
Inserting 6
Received 6
Inserting 7
Received 7
Inserting 8
Received 8
Inserting 9
Received 9
有些是有序的,但有些是交换的。为什么会这样?当我的 withSuccess 回调被调用时,我对文档的更改不应该生效吗?是否有可以将回调传递给的其他函数?
您看到的是异步执行引起的竞争条件的结果,因为JavaScript代码与Google Apps Script测试函数执行的操作不同,尽管您努力确保每个setText()
和getText()
函数调用都是同步的。(对于不熟悉这些概念的人来说,这里有一个很好的一般解释:异步与同步执行,它的真正含义是什么?
问题是,这里涉及另一个级别的异步性,因为您正在访问的Google文档的每个"用户"都会获得自己的副本,该副本(至少在概念上)与主副本同步。
test()
函数在单个 Google Apps 脚本执行实例的上下文中运行。该实例与文档的一个副本相关联,并且所有后续读取和写入都与该副本相关联。实际效果是,您的脚本在进行更改后立即看到它们。
将此与在客户端浏览器中运行的 JavaScript 的行为进行对比。在那里,每个google.script.run
调用都会在Google的服务器上创建一个新的,唯一的Google Apps Script执行实例,并具有自己唯一的Google文档副本。调用setText()
时,它会修改其文档副本,然后与主控文档同步。当getText()
运行时,它会获取当前主控文档的副本,并从中检索内容。如果上一个setText()
更改的同步已完成,您将获得所需的输出。如果同步没有完成 - 好吧,你会得到你得到的。
你能做些什么呢?只需最少的代码更改,您就可以延迟来自 JavaScript 客户端的getText()
调用,只要您认为有必要保证成功。需要注意的是,今天足够的延迟可能不是明天,因此不可靠。
function receive() {
setTimeout(
google.script.run.withSuccessHandler(function(text) {
log("Received " + text);
i++;
if(i < 10)
insert();
}).getText(),
2000 // 2 second delay before calling getText()
);
}
为了保证同步性,您需要设计一个更复杂的系统,例如一些始终运行的"服务器"进程,并需要操作文档的单个副本。
- 创建一个类似链接的按钮,并通过Javascript函数打开一个新的弹出窗口
- 将函数的上下文应用于javascript变量
- 如何在JavaScript中将字符串转换为函数引用
- 用嵌套函数和默认函数定义函数
- 使用 jQuery 的 .on 函数如何获取事件的原始元素
- 无法导出函数expressjs/requestjs中的变量
- 函数参数中的数据与指定变量之间的任何性能差异
- JQuery合并了keyup和focusout两个函数
- ES6构造函数返回基类的实例
- 监视函数从服务返回不起作用,但作用域函数起作用
- 我可以在json对象中添加一个函数吗
- AngularJS:我可以跳过函数参数回调吗
- 如何使jQuery插件函数可调用以供独立使用,而不在集合上操作
- JavaScript数组排序(函数)用于对表行进行排序,而不是排序
- jquery点击函数select&取消选择
- 拨打'父亲'函数形式a'儿童'ReactJS中的组件
- Node.js v6.2.0类扩展不是函数错误
- 比较从函数和生成的日期对象
- jQuery中是否内置了任何字符串格式化函数
- 客户端 JavaScript 从服务器端文档集和获取函数接收过时的值