由于事件触发而中断函数



假设我有以下函数:

let x = 1
function countForever() {
setTimeout(function() {
console.log(x)
x = x +1
countForever()
});
}

我们还有一个对象,其中包含一个名为e的事件发射器。e有一个状态,如果该状态不等于 3,我们希望终止我们的函数。我们可以通过以下方式实现这一目标:

let x = 1
function countForever() {
if (e.state != 3) return
setTimeout(function() {
console.log(x)
x = x +1
countForever()
});
}

这行得通。然而,我真正的非示例函数中有更多的步骤,我发现自己不断检查状态,通过函数 8-10 倍。

鉴于e是一个事件发射器,我想在状态更改时捕获这些更改并终止函数。幸运的是,e已经有一个我们可以监听的事件:

e.on('state_changed' , function(new_state) {
// Kill countForever
})

如何从其范围之外停止执行此函数?

编辑:我不知道为什么我用setTimeout写了一个示例函数,看来我有很大的误导性。这是一个更好的:

async function functionToKill() {
if (e.state != 3) return
thing1 = await functionThatTakesALongTime()
if (e.state != 3) return
thing2 = await secondFunctionThatTakesALongTime()
if (e.state != 3) return
thing3 = await thirdFunctionThatTakesALongTime()  
//.....
if (e.state != 3) return
thing10 = await tenthFunctionThatTakesALongTime()  
}
// e is an event emitter
e.on('state_changed' , function(new_state) {
// Kill/interrupt functionToKill
})

实际上,在函数中,我一遍又一遍地不断检查状态,并在状态更改时返回。我觉得这不干净,并且想从事件发射器触发的外部调用中做相当于return

在示例函数中,您没有给我们很多内容,但这里有一个关于该代码的想法。 您使用主承诺,当被拒绝时,会导致您的await操作序列中止:

// create deferred object so it can be rejected externally
Promise.Deferred = function() {
if (!(this instanceof Promise.Deferred)) {
return new Promise.Deferred();
}
let p = this.promise = new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
this.then = this.promise.then.bind(p);
this.catch = this.promise.catch.bind(p);
if (this.promise.finally) {
this.finally = this.promise.finally.bind(p);
}
}
// shared promise, when rejected our function stops advancing to more operations
let killPromise = new Promise.Deferred();
function raceKill(p) {
return Promise.race(killPromise, p);
}
async function functionToKill() {
try {
thing1 = await raceKill(functionThatTakesALongTime());
thing2 = await raceKill(secondFunctionThatTakesALongTime());
thing3 = await raceKill(thirdFunctionThatTakesALongTime());
//.....
thing10 = await raceKill(tenthFunctionThatTakesALongTime());
} catch(e) {
// perhaps handle kill errors separately from actual function rejection errors
}
}
// e is an event emitter
e.on('state_changed' , function(new_state) {
// Kill/interrupt functionToKill
killPromise.reject(new Error("state_changed"));
})

这种带有Promise.race()的结构具有一点优势,因为它甚至不会等待functionThatTakesALongTime()完成即可中止(当您的伪代码能够检查e.state时(。 当您拒绝killPromise时,它会立即中止。 其他异步操作不会神奇地取消。 它仍然会做它将要做的事情,但你的functionToKill()不会等待它。

对于实际代码,可能比使用共享范围变量(如killPromise、传递参数、共享某些内容作为对象属性等(更优雅的方法来实现这一点...... 但是,希望这能向您展示大致的想法。

kill countForever? 您可以使用计时器等变量保存 setTimeout 函数的返回值,然后在触发事件时清除state_changed超时(timer(。我不知道我的理解是否正确?

最新更新