Javascript 重新进入安全异步函数执行
我有一个Javascript 重新进入安全异步函数执行,javascript,coffeescript,windows-runtime,promise,winrt-async,Javascript,Coffeescript,Windows Runtime,Promise,Winrt Async,我有一个saveAsync方法,可以从应用程序的其他几个部分调用。其中一些代码路径不是来自主UI线程,而是来自其他异步操作,如从套接字/文件读取数据 在我的saveAsync函数中,我调用WinRT的StorageFile流写入函数。一次只允许一个文件的写入程序。因此,我必须将对我的saveAsync函数的多个连续调用排队,并按顺序执行它们。这是我现在正在使用的代码: SaveableMixin = { savesPending: 0, saveAsync: function() {
saveAsync
方法,可以从应用程序的其他几个部分调用。其中一些代码路径不是来自主UI线程,而是来自其他异步操作,如从套接字/文件读取数据
在我的saveAsync
函数中,我调用WinRT
的StorageFile
流写入函数。一次只允许一个文件的写入程序。因此,我必须将对我的saveAsync
函数的多个连续调用排队,并按顺序执行它们。这是我现在正在使用的代码:
SaveableMixin = {
savesPending: 0,
saveAsync: function() {
self = this
logger.debug("Save requested (_cachedFile=" + self._cachedFile + ")");
if (self.saving) {
self.savesPending += 1;
logger.debug("saveAsync: already saving, " + self.savesPending + " pending now");
return self.saving;
}
return self.saving = getFileNameAsync(self.serialNumber).then(function(file) {
logger.debug("saveAsync: saving...");
return self.node.ownerDocument.saveToFileAsync(file);
}).then(null, (function(error) {
return logger.error("saveAsync: failed but " + self.savesPending + " saves pending - good luck!", error);
}).then((function() {
logger.debug("saveAsync: saved and " + self.savesPending + " pending");
self.saving = null;
if (self.savesPending) {
self.savesPending = 0;
return self.saveAsync();
}
});
}
}
CoffeeScript原始代码:
savesPending: 0
saveAsync: () ->
logger.debug("Save requested (_cachedFile=#{@_cachedFile})")
if @saving
@savesPending += 1
logger.debug("saveAsync: already saving, #{@savesPending} pending now")
return @saving
@saving = getCachedFile(@serialNumber)
.then (file) =>
logger.debug("saveAsync: saving...")
@node.ownerDocument.saveToFileAsync(file)
.then null, (error) =>
logger.error("saveAsync: failed with inspection #{@serialNumber} but #{@savesPending} saves pending - good luck!", error)
.then =>
logger.debug("saveAsync: saved and #{@savesPending} pending")
@saving = null
if @savesPending
@savesPending = 0
return @saveAsync()
如您所见,我记得上次保存时承诺知道操作正在运行。然而,我仍然会得到一个访问被拒绝
异常,原因是某些代码路径设法将保存
视为空,因此认为现在保存操作正在进行。当变量即将分配给第一个调用者时,当第二个异步操作(例如套接字读取)完成并调用saveAsync
,而第一个调用者获得分配的saving
变量时,似乎会发生这种情况
<>在C++中,我会使用锁来防止。在JavaScript世界中可以做什么
更新
这将在调试器中生成以下输出:
2014-12-07 23:46:52,286 - [inspection - DEBUG] - saveAsync: get file for save 0
2014-12-07 23:46:52,289 - [inspection - DEBUG] - saveAsync: get file for save 0
2014-12-07 23:46:52,349 - [inspection - DEBUG] - saveAsync: got file for save 0 ...
2014-12-07 23:46:52,444 - [inspection - DEBUG] - saveAsync: got file for save 0 ...
2014-12-07 23:46:52,446 - [inspection - DEBUG] - saveAsync: get file for save 1
2014-12-07 23:46:52,447 - [inspection - DEBUG] - saveAsync: got file for save 1 ...
当然,这是对有问题的文件的双重访问,并与AV一起崩溃。在JavaScript世界中,您可以使用承诺来实现这一点,承诺抽象了一系列异步操作,您可以将其用作队列
SaveableMixin = {
queue: WinJS.promise.as(), // empty start of queue
saveAsync: function() {
this.queue = this.queue.then(function(){ // update the queue
return getFileNameAsync(self.serialNumber).then(function(file) {
logger.debug("saveAsync: saving...");
return self.node.ownerDocument.saveToFileAsync(file);
})..then(null, (function(error) {
return logger.error("saveAsync: failed good luck!", error);
}).then((function() {
logger.debug("saveAsync: saved and " + self.savesPending + " pending");
});
}
}
不确定这是否是问题的原因,但您没有正确关闭括号。把这段代码放到jslinter或soemthing中,你会看到一些括号被打开了。谢谢,这段代码是我从coffeescript源代码中手工编辑的,我删除了一些杂乱的内容。是的,一些括号可能没有正确闭合。
self
缺少一个var
源于咖啡清理?你可能还想发布原始的咖啡脚本。我不确定排队是如何工作的<代码>保存开销在每次发出请求时都会递增,而保存仍在进行,但附带的数据(.serialNumber
?)存储在哪里?为什么savespensing
会重置为0,而不是递减?请详细说明:-)@Bergi。serialNumber是您将该类与之混合的类的成员。我增量saveexpensing
只知道在保存文件时,有更多的请求保存它。由于所有这些请求最终都会保存XML的最新状态,因此我只需要知道是否有挂起的保存,并再次保存文件。我本可以使用boolan而不是递增计数器,但这样我就可以看到在保存过程中我接到了多少个呼叫。这可能与我当前遇到的竞争条件相同。在分配this.queue的“n”时刻,另一个完成处理程序可能会调用saveAsync并将this.queue分配给其他对象。否?@philk Fun fact-大多数上下文中,尤其是WinJS应用程序中的JavaScript都是单线程的。在这些上下文中,它是基于事件和单线程的。没有两个作业可以同时进行。我也这么认为。但是我的代码已经可以用了,不是吗?我可以看到进入saveAsync方法的方法的堆栈跟踪,它们都来自主线程,是的。然而,它可能试图同时从两个不同的代码路径写入文件。有一点需要澄清:JavaScript中的UI线程是单线程的,但WinRT异步操作确实会委托给其他线程。其他线程对已完成/错误/进度处理程序的回调将进入UI线程,因此您一次只能处理一个操作的结果,但多个操作可能同时发生,因此会发生冲突。@KraigBrockschmidt MSFT JavaScript是单线程的,不是吗?我的意思是,就像在Node中一样,在其他线程中运行的其他东西不是userland代码。
SaveableMixin = {
queue: WinJS.promise.as(), // empty start of queue
saveAsync: function() {
this.queue = this.queue.then(function(){ // update the queue
return getFileNameAsync(self.serialNumber).then(function(file) {
logger.debug("saveAsync: saving...");
return self.node.ownerDocument.saveToFileAsync(file);
})..then(null, (function(error) {
return logger.error("saveAsync: failed good luck!", error);
}).then((function() {
logger.debug("saveAsync: saved and " + self.savesPending + " pending");
});
}
}