- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个JavaScript(EmberJS + Electron)应用程序,需要执行异步任务序列。这是一个简化的示例:
发送消息到远程设备
不到t1
秒后收到响应
传送其他讯息
不到t2
秒后收到第二个响应
显示成功消息
对于简单的情况,使用Promises似乎很容易实现:1然后2然后3 ...当合并了超时时,它会变得有些棘手,但是Promise.race
和Promise.all
似乎是合理的解决方案。
但是,我需要允许用户能够优雅地取消序列,并且我正在努力思考这样做的明智方法。首先想到的是在每个步骤中进行某种轮询,以查看是否已在某个位置设置了变量以指示应取消该序列。当然,这有一些严重的问题:
效率低下:浪费了大部分轮询时间
无响应:必须轮询才能引入额外的延迟
Smelly:我认为这无疑是不雅的。 cancel
事件与时间完全无关,因此不需要使用计时器。 isCanceled
变量可能需要超出promise的范围。等等
我的另一个想法是,也许到目前为止,所有事情都与另一个仅在用户发送取消信号时才解决的承诺相冲突。这里的主要问题是,正在运行的单个任务(用户要取消)不知道它们需要停止,回滚等,因此即使从竞争中获得承诺解决方案的代码都能正常工作,其他诺言中的代码不会得到通知。
很久以前就有talk about cancel-able promises,但是在我看来,该提案已撤回,因此尽管我认为BlueBird promise library支持该想法,但也不会很快纳入ECMAScript。我正在制作的应用程序已经包含RSVP promise library,因此我并不是真的想引入另一个,但是我想这是一个潜在的选择。
还有什么可以解决这个问题的呢?
我应该完全使用诺言吗?通过发布/订阅事件系统或诸如此类的事情可以更好地解决此问题?
理想情况下,我想将被取消的关注从每个任务中分离出来(就像Promise
对象如何处理异步的关注一样)。如果取消信号可以是传入/注入的信号,那也很好。
尽管没有图形技能,但我还是尝试通过制作下面的两张图来说明我正在尝试做的事情。如果您发现它们令人困惑,请随时忽略它们。
最佳答案
如果我正确理解您的问题,则可能是以下解决方案。
简单超时
假设您的主线代码如下所示:
send(msg1)
.then(() => receive(t1))
.then(() => send(msg2))
.then(() => receive(t2))
.catch(() => console.log("Didn't complete sequence"));
receive
类似于:
function receive(t) {
return new Promise((resolve, reject) => {
setTimeout(() => reject("timed out"), t);
receiveMessage(resolve, reject);
});
}
receiveMessage
,该API将两个回调作为参数,一个用于成功,一个用于失败。
receive
简单地包装
receiveMessage
并加上超时,如果在
t
解析之前经过了
receiveMessage
时间,则超时将拒绝承诺。
cancelablePromise
:
function cancelablePromise(executor, canceler) {
return new Promise((resolve, reject) => {
canceler.then(e => reject(`cancelled for reason ${e}`));
executor(resolve, reject);
});
}
(resolve, reject)
。我们传入的取消器是一个诺言,当实现时,它取消(拒绝)我们正在创建的诺言。因此,
cancelablePromise
的工作方式与
new Promise
完全相同,只是添加了第二个参数,即用于取消的承诺。
var canceler1 = new Promise(resolve =>
document.getElementById("cancel1", "click", resolve);
);
send(msg1)
.then(() => cancelablePromise(receiveMessage, canceler1))
.then(() => send(msg2))
.then(() => cancelablePromise(receiveMessage, canceler2))
.catch(() => console.log("Didn't complete sequence"));
class CancelablePromise extends Promise {
constructor(executor, canceler) {
super((resolve, reject) => {
canceler.then(reject);
executor(resolve, reject);
}
}
send(msg1)
.then(() => new CancelablePromise(receiveMessage, canceler1))
.then(() => send(msg2))
.then(() => new CancelablePromise(receiveMessage, canceler2))
.catch(() => console.log("Didn't complete sequence"));
Promise
之类的内置子类。如果以ES5为目标,则TypeScript发出的代码可能不起作用。
canceler
在我们开始执行序列或调用
cancelablePromise(receiveMessage, canceler1)
之前已经实现,尽管诺言仍会按预期被取消(拒绝),但是执行程序仍会运行,开始执行接收逻辑-在最佳情况下可能会消耗我们不希望的网络资源。解决这个问题留作练习。
xhr.abort()
。
go
消息后开始:
function findPrime(n) {
return new Promise(resolve => {
var worker = new Worker('./find-prime.js');
worker.addEventListener('message', evt => resolve(evt.data));
worker.postMessage({cmd: 'go', n});
}
}
> findPrime(1000000).then(console.log)
< 15485863
"stop"
消息以终止其工作,并再次使用
canceler
诺言,则可以取消此操作,方法是:
function findPrime(n, canceler) {
return new Promise((resolve, reject) => {
// Initialize worker.
var worker = new Worker('./find-prime.js');
// Listen for worker result.
worker.addEventListener('message', evt => resolve(evt.data));
// Kick off worker.
worker.postMessage({cmd: 'go', n});
// Handle canceler--stop worker and reject promise.
canceler.then(e => {
worker.postMessage({cmd: 'stop')});
reject(`cancelled for reason ${e}`);
});
}
}
xhr.abort()
。
findPrime
执行器,如下所示:
const findPrimeExecutor = n => resolve => {
var worker = new Worker('./find-prime.js');
worker.addEventListener('message', evt => resolve(evt.data));
worker.postMessage({cmd: 'go', n});
return e => worker.postMessage({cmd: 'stop'}));
}
return
语句,它提供了一种取消正在进行的计算的方法。
cancelablePromise
的通用版本,我们将其称为
cancelablePromise2
,它知道如何与这些特殊的执行程序一起使用,这些执行程序返回一个函数来取消该过程:
function cancelablePromise2(executor, canceler) {
return new Promise((resolve, reject) => {
var cancelFunc = executor(resolve, reject);
canceler.then(e => {
if (typeof cancelFunc === 'function') cancelFunc(e);
reject(`cancelled for reason ${e}`));
});
});
}
var canceler = new Promise(resolve => document.getElementById("cancel", "click", resolve);
function chain(msg1, msg2, canceler) {
const send = n => () => cancelablePromise2(findPrimeExecutor(n), canceler);
const receive = () => cancelablePromise2(receiveMessage, canceler);
return send(msg1)()
.then(receive)
.then(send(msg2))
.then(receive)
.catch(e => console.log(`Didn't complete sequence for reason ${e}`));
}
chain(msg1, msg2, canceler);
canceler
承诺的那一刻,任何待处理的发送将被取消,而工作进程将在中途停止,和/或任何待处理的接收将被取消,并且该承诺将被拒绝,该拒绝顺着链条向下层叠到最终的
catch
。
canceler
承诺。但是,在大多数情况下,如我们在此处所做的那样,可以在纯用户域代码中处理取消逻辑而不会带来太多复杂性。
关于javascript - 在JavaScript中通过取消操作来管理复杂事件序列的实用/优雅方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41625444/
我有一个 html 格式的表单: 我需要得到 JavaScript在value input 字段执行,但只能通过表单的 submit .原因是页面是一个模板所以我不控制它(不能有
我管理的论坛是托管软件,因此我无法访问源代码,我只能向页面添加 JavaScript 来实现我需要完成的任务。 我正在尝试用超链接替换所有页面上某些文本关键字的第一个实例。我还根据国家/地区代码对这些
我正在使用 JS 打开新页面并将 HTML 代码写入其中,但是当我尝试使用 document.write() 在新页面中编写 JS 时功能不起作用。显然,一旦看到 ,主 JS 就会关闭。用于即将打开的
提问不是为了解决问题,提问是为了更好地理解系统 专家!我知道每当你将 javascript 代码输入 javascript 引擎时,它会立即由 javascript 引擎执行。由于没有看过Engi
我在一个文件夹中有两个 javascript 文件。我想将一个变量的 javascript 文件传递到另一个。我应该使用什么程序? 最佳答案 window.postMessage用于跨文档消息。使
我有一个练习,我需要输入两个输入并检查它们是否都等于一个。 如果是 console.log 正则 console.log false 我试过这样的事情: function isPositive(fir
我正在做一个Web应用程序,计划允许其他网站(客户端)在其页面上嵌入以下javascript: 我的网络应用程序位于 http://example.org 。 我不能假设客户端网站的页面有 JQue
目前我正在使用三个外部 JS 文件。 我喜欢将所有三个 JS 文件合而为一。 尽一切可能。我创建 aio.js 并在 aio.js 中 src="https://code.jquery.com/
我有例如像这样的数组: var myArray = []; var item1 = { start: '08:00', end: '09:30' } var item2 = {
所以我正在制作一个 Chrome 扩展,它使用我制作的一些 TamperMonkey 脚本。我想要一个“主”javascript 文件,您可以在其中包含并执行其他脚本。我很擅长使用以下行将其他 jav
我有 A、B html 和 A、B javascript 文件。 并且,如何将 A JavaScript 中使用的全局变量直接移动到 B JavaScript 中? 示例 JavaScript) va
我需要将以下整个代码放入名为 activate.js 的 JavaScript 中。你能告诉我怎么做吗? var int = new int({ seconds: 30, mark
我已经为我的 .net Web 应用程序创建了母版页 EXAMPLE1.Master。他们的 I 将值存储在 JavaScript 变量中。我想在另一个 JS 文件中检索该变量。 示例1.大师:-
是否有任何库可以用来转换这样的代码: function () { var a = 1; } 像这样的代码: function () { var a = 1; } 在我的浏览器中。因为我在 Gi
我收到语法缺失 ) 错误 $(document).ready(function changeText() { var p = document.getElementById('bidp
我正在制作进度条。它有一个标签。我想调整某个脚本完成的标签。在找到可能的解决方案的一些答案后,我想出了以下脚本。第一个启动并按预期工作。然而,第二个却没有。它出什么问题了?代码如下: HTML:
这里有一个很简单的问题,我简单的头脑无法回答:为什么我在外部库中加载时,下面的匿名和onload函数没有运行?我错过了一些非常非常基本的东西。 Library.js 只有一行:console.log(
我知道 javascript 是一种客户端语言,但如果实际代码中嵌入的 javascript 代码以某种方式与在控制台上运行的代码不同,我会尝试找到答案。让我用一个例子来解释它: 我想创建一个像 Mi
我如何将这个内联 javascript 更改为 Unobtrusive JavaScript? 谢谢! 感谢您的回答,但它不起作用。我的代码是: PHP js文件 document.getElem
我正在寻找将简单的 JavaScript 对象“转储”到动态生成的 JavaScript 源代码中的最优雅的方法。 目的:假设我们有 node.js 服务器生成 HTML。我们在服务器端有一个对象x。
我是一名优秀的程序员,十分优秀!