Await dispatchEvent:当侦听器异步时如何同步侦听 dispatchEvent
Await dispatchEvent: How to listen synchronously to a dispatchEvent when listener is async
为了开发一个软件插件,我需要监听一个由 dispatchEvent
产生的事件,并在接收到这个事件时执行一些操作。重要的是我的动作应该在软件继续执行dispatchEvent
.
之后的代码之前完成
因为dispatchEvent
是同步的,所以应该是这样的。。。可惜我的动作是异步的(基本上需要等视频被求到),这样的话dispatchEvent
在我自己的代码结束之前继续。当被调用函数是异步的时,是否也可以获得 dispatchEvent
的同步行为?
示例:
我想要以下代码来生成输出:
Putting the clothes in the washing machine.
Machine started...
Machine ended...
Picking the washed clothes.
可惜洗衣机还没结束就把衣服挑了:
Putting the clothes in the washing machine.
Machine started...
Picking the washed clothes.
Machine ended...
我使用了这个代码:
var button = document.getElementById('button');
button.addEventListener('click', event => {
console.log("Putting the clothes in the washing machine.");
const machineResult = button.dispatchEvent(new CustomEvent('startmachine', {
'detail': {
timeProgram: 3000
}
}));
if (machineResult.defaultPrevented) {
console.log("Picking the dirty clothes.");
} else {
console.log("Picking the washed clothes.");
}
});
button.addEventListener('startmachine', async event => {
console.log("Machine started...");
await new Promise(r => setTimeout(r, event.detail.timeProgram));
console.log("Machine ended...");
});
<button id="button">Wash my clothes</button>
编辑:找到了一个我不喜欢的脏解决方案
显然,这似乎是不可能的,我使用了一种不同的方法,不幸的是 需要在代码 dispatchEvent
之后进行一些更改(因为我不负责这部分代码,我更喜欢在 dispatchEvent
).
之后不更改代码的方法
想法是在事件中添加一个数组,每个侦听器都可以放置一个异步函数。然后,在 dispatchEvent
完成后,代码执行此数组中的所有函数,如果有 returns false
则认为事件已中止。
var button = document.getElementById('button');
button.addEventListener('click', async event => {
console.log("Putting the clothes in the washing machine.");
var listOfActions = [];
const machineResult = button.dispatchEvent(new CustomEvent('startmachine', { 'detail': {timeProgram: 3000, listOfActions: listOfActions} }));
results = await Promise.all(listOfActions.map(x => x()));
if (machineResult.defaultPrevented || !results.every(x => x != false)) { // Do not use == true or boolean to ensure returning nothing does not abort.
console.log("Picking the dirty clothes.");
} else {
console.log("Picking the washed clothes.");
}
});
button.addEventListener('startmachine', event => {
event.detail.listOfActions.push( async () => {
console.log(">>> Machine started...");
await new Promise(r => setTimeout(r, event.detail.timeProgram));
console.log("<<< Machine ended...");
// If you want to say that the clothes are dirty:
// return false
});
});
<button id="button">Wash my clothes</button>
编辑 2
使用 promise 更好地处理错误:
var button = document.getElementById('button');
button.addEventListener('click', async event => {
console.log("Putting the clothes in the washing machine.");
var listOfActions = [];
let cancelled = !button.dispatchEvent(new CustomEvent('startmachine', { 'detail': {timeProgram: 3000, listOfActions: listOfActions} }));
results = await Promise.all(listOfActions);
// Do not use == true or boolean to ensure returning nothing does not abort.
cancelled = cancelled || !results.every(x => x != false)
if (cancelled) {
console.log("Picking the dirty clothes.");
} else {
console.log("Picking the washed clothes.");
}
});
button.addEventListener('startmachine', event => {
event.detail.listOfActions.push((async () => {
console.log(">>> Machine started...");
await new Promise(r => setTimeout(r, event.detail.timeProgram));
console.log("<<< Machine ended...");
// If you want to say that the clothes are dirty:
//return false
})());
// ^-- The () is useful to push a promise and not an async function.
// I could also have written let f = async () => { ... }; event....push(f())
});
<button id="button">Wash my clothes</button>
Is it possible to also get a synchronous behavior for dispatchEvent
when the called function is asynchronous?
不,不是。
The idea is to add an array in the event where each listener can put an async function
. Then, after dispatchEvent
is done, the code executes all functions in this array
是的,这是个好主意。然而,我会把它变成一个承诺数组,而不是一个函数数组。
Web 平台 API 在 ExtendableEvent
中使用相同的模式。不幸的是,该构造函数仅在服务工作者内部可用:-/
为了开发一个软件插件,我需要监听一个由 dispatchEvent
产生的事件,并在接收到这个事件时执行一些操作。重要的是我的动作应该在软件继续执行dispatchEvent
.
因为dispatchEvent
是同步的,所以应该是这样的。。。可惜我的动作是异步的(基本上需要等视频被求到),这样的话dispatchEvent
在我自己的代码结束之前继续。当被调用函数是异步的时,是否也可以获得 dispatchEvent
的同步行为?
示例:
我想要以下代码来生成输出:
Putting the clothes in the washing machine.
Machine started...
Machine ended...
Picking the washed clothes.
可惜洗衣机还没结束就把衣服挑了:
Putting the clothes in the washing machine.
Machine started...
Picking the washed clothes.
Machine ended...
我使用了这个代码:
var button = document.getElementById('button');
button.addEventListener('click', event => {
console.log("Putting the clothes in the washing machine.");
const machineResult = button.dispatchEvent(new CustomEvent('startmachine', {
'detail': {
timeProgram: 3000
}
}));
if (machineResult.defaultPrevented) {
console.log("Picking the dirty clothes.");
} else {
console.log("Picking the washed clothes.");
}
});
button.addEventListener('startmachine', async event => {
console.log("Machine started...");
await new Promise(r => setTimeout(r, event.detail.timeProgram));
console.log("Machine ended...");
});
<button id="button">Wash my clothes</button>
编辑:找到了一个我不喜欢的脏解决方案
显然,这似乎是不可能的,我使用了一种不同的方法,不幸的是 需要在代码 dispatchEvent
之后进行一些更改(因为我不负责这部分代码,我更喜欢在 dispatchEvent
).
想法是在事件中添加一个数组,每个侦听器都可以放置一个异步函数。然后,在 dispatchEvent
完成后,代码执行此数组中的所有函数,如果有 returns false
则认为事件已中止。
var button = document.getElementById('button');
button.addEventListener('click', async event => {
console.log("Putting the clothes in the washing machine.");
var listOfActions = [];
const machineResult = button.dispatchEvent(new CustomEvent('startmachine', { 'detail': {timeProgram: 3000, listOfActions: listOfActions} }));
results = await Promise.all(listOfActions.map(x => x()));
if (machineResult.defaultPrevented || !results.every(x => x != false)) { // Do not use == true or boolean to ensure returning nothing does not abort.
console.log("Picking the dirty clothes.");
} else {
console.log("Picking the washed clothes.");
}
});
button.addEventListener('startmachine', event => {
event.detail.listOfActions.push( async () => {
console.log(">>> Machine started...");
await new Promise(r => setTimeout(r, event.detail.timeProgram));
console.log("<<< Machine ended...");
// If you want to say that the clothes are dirty:
// return false
});
});
<button id="button">Wash my clothes</button>
编辑 2
使用 promise 更好地处理错误:
var button = document.getElementById('button');
button.addEventListener('click', async event => {
console.log("Putting the clothes in the washing machine.");
var listOfActions = [];
let cancelled = !button.dispatchEvent(new CustomEvent('startmachine', { 'detail': {timeProgram: 3000, listOfActions: listOfActions} }));
results = await Promise.all(listOfActions);
// Do not use == true or boolean to ensure returning nothing does not abort.
cancelled = cancelled || !results.every(x => x != false)
if (cancelled) {
console.log("Picking the dirty clothes.");
} else {
console.log("Picking the washed clothes.");
}
});
button.addEventListener('startmachine', event => {
event.detail.listOfActions.push((async () => {
console.log(">>> Machine started...");
await new Promise(r => setTimeout(r, event.detail.timeProgram));
console.log("<<< Machine ended...");
// If you want to say that the clothes are dirty:
//return false
})());
// ^-- The () is useful to push a promise and not an async function.
// I could also have written let f = async () => { ... }; event....push(f())
});
<button id="button">Wash my clothes</button>
Is it possible to also get a synchronous behavior for
dispatchEvent
when the called function is asynchronous?
不,不是。
The idea is to add an array in the event where each listener can put an
async function
. Then, afterdispatchEvent
is done, the code executes all functions in this array
是的,这是个好主意。然而,我会把它变成一个承诺数组,而不是一个函数数组。
Web 平台 API 在 ExtendableEvent
中使用相同的模式。不幸的是,该构造函数仅在服务工作者内部可用:-/