如何暂停对一个函数的调用,直到独立调用另一个函数



我在下面有工作代码,但我觉得必须有一个更干净的解决方案,我认为承诺或回调在我的情况下不起作用。

我有一个主函数 (foo),它在 x 毫秒后独立调用自己(在我的实际代码中,它反复执行此操作)。当它调用自身时,它会递增存储在对象中的值。

我有第二个函数(bar),有时会被随机调用。但是,我希望(在某些情况下)能够暂停此函数的执行,直到下次再次调用主函数 (foo)。

在下面的工作示例中,bar在调用bar时存储prop的当前值,然后不断重复检查prop的值,直到值发生变化。当值不再为 == 时,bar执行else中的代码。这有效,但并不干净,如果bar只是侦听prop更改(或foo调用),并且在那一刻被执行,时间也不那么准确。

我不相信承诺或回调会起作用,因为它们通常用于第二个函数作为参数传递的情况。就我而言,我的第二个功能是有另一份工作并且已经在重复做自己的工作。我也不希望再次执行第二个函数,我只希望它的调用允许函数 1 完成自己的执行。

对于我的实际情况,使用延迟也不理想。

更多详情

我的实际程序通过随机触发要播放的音频文件来制作音乐。bar()是确定播放声音的所有方式/属性(持续时间、音量、淡入/淡出等)的函数。

foo()是一个主函数,用于确定程序在歌曲的哪个部分。因此,每次调用foo()时,它都会递增程序/歌曲所处的阶段(即 1、2、3、4),并且它还调用许多函数,更新属性,从而更改允许get()函数播放声音的方式。

因此,该程序主要随机播放声音(例如不在刚性节拍/小节上),我希望在某些情况下可以选择在小节上播放它们。由于foo()是跟踪此时间的函数,因此我添加了get()功能,以便当声音未在节拍上触发时,它会延迟直到分配的节拍发生,然后被允许播放。我有该功能工作。

当一个声音被指定落在已经过去的节拍上时,诀窍就出现了。在这些情况下,我需要暂停get()直到下一个柱线(即,再次调用foo()时)。在正常的音乐情况下,时间(每分钟节拍数)是固定的,这样我就可以简单地进行数学运算并设置超时,直到正确的时间。但是,我的程序有点非传统,每次调用foo()时持续时间都会更改。因此,下一个柱线的持续时间并不知道。

因此,总而言之,bar()(声音)被调用,它存储了一大堆参数,这些参数决定了声音的播放方式。我需要bar()在调用它之后暂停,直到它听到/看到foo()再次被调用,然后才完成播放声音的工作。

这是我的工作示例。

const config = {
object: {
prop: 1
},
};
(function foo() {
setTimeout(function() {
config.object.prop = 3;
console.log('foo changed the value of config.object.prop');
}, 4000);
})();
bar();
function bar() {
var prop = config.object.prop;
(function nar() {
if (prop == config.object.prop) {
console.log('sorry, still waiting for config.object.prop to change');
setTimeout(function() {
nar();
}, 1000);
} else {
console.log('Executed only after config.object.prop changed!!!');
}
})();
}

这是回调和观察者模式的完美用例。

主进程应生成节拍事件,并触发正在等待它们的函数。

您可以使用消息总线框架来帮助您解决此问题,或者您甚至可以使用一个函数来获得来自主进程的下一个节拍的承诺,但自行开发的解决方案也可以工作。您所需要的只是一个侦听器函数数组,bar将功能的节拍部分添加到该列表中,foo从该列表中调用(和删除)函数。

你可以有一个布尔值来决定每次执行 foo() 时是否应该调用 nar(),并让 bar() 在函数需要运行时将布尔值设置为 true。

let runNar = false;
(function foo() {
setTimeout(function() {
	if (runNar === true) {
		nar();
		runNar = false;
	}
console.log('foo changed the value of config.object.prop');
}, 4000);
})();
bar();
function bar() {
	runNar = true;
};
function nar() {
	console.log('Excuted when foo() is called');
};

也可以使用Promise 来解决,但我认为有更好的解决方案:
使用setters 或Proxy

它是如何工作的?

  • Setter:
    setter 可以定义伪属性,伪属性不能有值,但如果你尝试设置该属性的值,将调用一个函数,接收新值作为参数。

语法:

var obj={
prop:1,
set anotherProp(value){
//Handle set:
this.prop=value
}
}
obj.anotherProp=5
obj.prop //5

翻译成您的案例:

const config = {
object: {
prop: 1,
set setterProp(value){
this.prop=value;
bar()
}
},
};
(function foo() {
setTimeout(function() {
console.log('foo changed the value of config.object.prop');
config.object.setterProp = 3;
}, 4000);
})();
function bar() {
console.log('Executed only after config.object.prop changed!!!');
}

  • 代理:使用 Proxy 对象,您可以执行类似 setter 的操作,但是:
    1. 代理可用于监视和控制对对象的任何操作(获取,设置,删除,函数调用,类构造等)。
    2. 与资源库不同,代理监视对象的所有属性。

语法:

var obj={
prop:1
}
var proxy=new Proxy(obj,{
set:function(obj,prop,value){
//Handle set:
obj[prop]=value;
}
})
proxy.prop=5
proxy.prop //5
obj.prop   //5

翻译成您的案例:

const config = {
object: {
prop: 1
},
};
const proxy=new Proxy(config.object, {
set: function(obj,prop,value){
//Handle set:
obj[prop]=value;
if(prop==='prop'){bar()};
}
});
(function foo() {
setTimeout(function() {
console.log('foo changed the value of config.object.prop');
proxy.prop = 3;
}, 4000);
})();
function bar(){
console.log('Executed only after config.object.prop changed!!!');
}

好吧,但是如果我不想每次都打电话给酒吧怎么办!

const barList=[]
const config = {
object: {
prop: 1
},
};
const proxy=new Proxy(config.object, {
set: function(obj,prop,value){
//Handle set:
obj[prop]=value;
if(prop==='prop'){
barList.filter(x=>{
bar(...x)
return false
})
};
}
});
(function foo() {
setTimeout(function() {
console.log('foo changed the value of config.object.prop');
proxy.prop = 3;
}, 4000);
})();
function callBar(...args){
barList.push(args)
}
function bar(...argument){
console.log('Executed only after config.object.prop changed!!!', ...argument);
}
callBar();
callBar('with','some','arguments');

最新更新