即使满足中断条件,递归函数也不会终止 - JavaScript
Recursive function not terminating even when break condition is met - JavaScript
我正在构建一个 React.JS 组件,单击按钮时,它会从 JokeAPI
中获取一个笑话,并使用 Web Synthesis 文本转语音 API 对其进行叙述。当通过全局布尔变量按下 stop
按钮时,我想停止这种旁白和取笑话。但是,该函数并没有停止并继续递归执行。
JokeComponent.js
export default function JokeComponent() {
const [jokeState, jokeStateSetter] = useState();
var RUNNING
const fetchAndNarrate = () => {
if(RUNNING){
axios.get("https://v2.jokeapi.dev/joke/Any").then((res) => {
console.log(res.data);
//the returned joke is twopart ie. with a setup and a delivery
if (res.data.type === "twopart") {
jokeStateSetter(res.data.setup);
//If speech synthesis compatible, narrate
if ("speechSynthesis" in window) {
say(res.data.setup).then(() => {
setTimeout(() => {
jokeStateSetter(res.data.delivery);
if ("speechSynthesis" in window) {
say(res.data.delivery).then(() => {
setTimeout(() => {
fetchAndNarrate();
}, 4000);
});
}
}, 2000);
});
//If speech synthesis not compatible with browser, just display the joke without narration
} else {
setTimeout(() => {
jokeStateSetter(res.data.delivery);
}, 4000);
fetchAndNarrate();
}
//the returned joke is in a single sentence
} else if (res.data.type === "single") {
jokeStateSetter(res.data.joke);
//If speech synthesis compatible
if ("speechSynthesis" in window) {
say(res.data.joke).then(() => {
setTimeout(() => {
fetchAndNarrate();
}, 4000);
});
}
//If speech synthesis not compatible with browser, just display the joke without narration
else {
setTimeout(() => {
jokeStateSetter(res.data.delivery);
}, 4000);
fetchAndNarrate();
}
}
// //the returned joke is of neither type
// else {
// fetchAndNarrate();
// }
});
} else
return
};
const say = function (text) {
return new Promise((resolve) => {
const utterance = new SpeechSynthesisUtterance(text);
utterance.onend = resolve;
window.speechSynthesis.speak(utterance);
});
};
return (
<div>
<h4>{jokeState}</h4>
<button
onClick={() => {
RUNNING = true
fetchAndNarrate();
}}>
Start
</button>
<button
onClick={() => {
RUNNING = false
//window.speechSynthesis.cancel();
}}>
Stop
</button>
</div>
);
}
当按下Start
按钮时,RUNNING
被设置为true
并执行递归函数fetchAndNarrate ()
。在内部,我使用 setTimeout
在笑话的设置和传送之间以及下一个笑话之间稍作停顿。这个递归函数背后的想法是让笑话一直持续到我按下 stop
按钮。按下时,我将 RUNNING
设置为 false。 say()
是一个函数,它 return 是一个承诺,当笑话被完整地讲述时,它就会解决。
预期的行为: 停止时,当前的笑话完成其叙述并且该函数应该在下一次迭代时失败 if(RUNNING)
条件和 return无需从 API.
中获取另一个笑话
观察到的行为: 停止时,当前的笑话完成了叙述并且该函数以某种方式继续运行并在下一次迭代中获取另一个笑话,尽管 RUNNING
被设置为false
并且功能永不停止。
我想我在那个函数中有太多嵌套的承诺,这可能是我搞砸的地方。我是 JavaScript 和 Promises 的新手,我不确定有这么多嵌套的 promises 是否理想。
请小弟帮忙
您在函数中将 运行 定义为局部变量。将其真正定义为全局,例如 window.RUNNING,然后是您的作品。
您可以使用 async/await 和一些辅助方法使您的代码更具可读性。当然,我使用过 fetch
,但同样适用于 axios。没有必要让它递归,一个简单的 while
循环就可以了。
async function run() {
while(running) {
var res = await fetch("https://v2.jokeapi.dev/joke/Any")
var json = await res.json();
if(json.type == "twopart") {
await say(json.setup);
await delay(1000);
await say(json.delivery);
}
else if(json.type == "single") {
await say(json.joke)
}
}
}
实例:
const say = function(text) {
out.innerHTML = text
return new Promise((resolve) => {
const utterance = new SpeechSynthesisUtterance(text);
utterance.onend = resolve;
window.speechSynthesis.speak(utterance);
});
};
const delay = t => new Promise(resolve => setTimeout(resolve, t))
const out = document.querySelector("#output");
const stop = document.querySelector("#stop")
stop.addEventListener("click", () => running = false)
let running = true
async function run() {
while (running) {
var res = await fetch("https://v2.jokeapi.dev/joke/Any")
var json = await res.json();
//console.log(json)
if (json.type == "twopart") {
await say(json.setup);
await delay(1000);
await say(json.delivery);
} else if (json.type == "single") {
await say(json.joke)
}
}
}
run()
<div id="output">
</div>
<button id="stop">
Stop
</button>
我正在构建一个 React.JS 组件,单击按钮时,它会从 JokeAPI
中获取一个笑话,并使用 Web Synthesis 文本转语音 API 对其进行叙述。当通过全局布尔变量按下 stop
按钮时,我想停止这种旁白和取笑话。但是,该函数并没有停止并继续递归执行。
JokeComponent.js
export default function JokeComponent() {
const [jokeState, jokeStateSetter] = useState();
var RUNNING
const fetchAndNarrate = () => {
if(RUNNING){
axios.get("https://v2.jokeapi.dev/joke/Any").then((res) => {
console.log(res.data);
//the returned joke is twopart ie. with a setup and a delivery
if (res.data.type === "twopart") {
jokeStateSetter(res.data.setup);
//If speech synthesis compatible, narrate
if ("speechSynthesis" in window) {
say(res.data.setup).then(() => {
setTimeout(() => {
jokeStateSetter(res.data.delivery);
if ("speechSynthesis" in window) {
say(res.data.delivery).then(() => {
setTimeout(() => {
fetchAndNarrate();
}, 4000);
});
}
}, 2000);
});
//If speech synthesis not compatible with browser, just display the joke without narration
} else {
setTimeout(() => {
jokeStateSetter(res.data.delivery);
}, 4000);
fetchAndNarrate();
}
//the returned joke is in a single sentence
} else if (res.data.type === "single") {
jokeStateSetter(res.data.joke);
//If speech synthesis compatible
if ("speechSynthesis" in window) {
say(res.data.joke).then(() => {
setTimeout(() => {
fetchAndNarrate();
}, 4000);
});
}
//If speech synthesis not compatible with browser, just display the joke without narration
else {
setTimeout(() => {
jokeStateSetter(res.data.delivery);
}, 4000);
fetchAndNarrate();
}
}
// //the returned joke is of neither type
// else {
// fetchAndNarrate();
// }
});
} else
return
};
const say = function (text) {
return new Promise((resolve) => {
const utterance = new SpeechSynthesisUtterance(text);
utterance.onend = resolve;
window.speechSynthesis.speak(utterance);
});
};
return (
<div>
<h4>{jokeState}</h4>
<button
onClick={() => {
RUNNING = true
fetchAndNarrate();
}}>
Start
</button>
<button
onClick={() => {
RUNNING = false
//window.speechSynthesis.cancel();
}}>
Stop
</button>
</div>
);
}
当按下Start
按钮时,RUNNING
被设置为true
并执行递归函数fetchAndNarrate ()
。在内部,我使用 setTimeout
在笑话的设置和传送之间以及下一个笑话之间稍作停顿。这个递归函数背后的想法是让笑话一直持续到我按下 stop
按钮。按下时,我将 RUNNING
设置为 false。 say()
是一个函数,它 return 是一个承诺,当笑话被完整地讲述时,它就会解决。
预期的行为: 停止时,当前的笑话完成其叙述并且该函数应该在下一次迭代时失败 if(RUNNING)
条件和 return无需从 API.
观察到的行为: 停止时,当前的笑话完成了叙述并且该函数以某种方式继续运行并在下一次迭代中获取另一个笑话,尽管 RUNNING
被设置为false
并且功能永不停止。
我想我在那个函数中有太多嵌套的承诺,这可能是我搞砸的地方。我是 JavaScript 和 Promises 的新手,我不确定有这么多嵌套的 promises 是否理想。
请小弟帮忙
您在函数中将 运行 定义为局部变量。将其真正定义为全局,例如 window.RUNNING,然后是您的作品。
您可以使用 async/await 和一些辅助方法使您的代码更具可读性。当然,我使用过 fetch
,但同样适用于 axios。没有必要让它递归,一个简单的 while
循环就可以了。
async function run() {
while(running) {
var res = await fetch("https://v2.jokeapi.dev/joke/Any")
var json = await res.json();
if(json.type == "twopart") {
await say(json.setup);
await delay(1000);
await say(json.delivery);
}
else if(json.type == "single") {
await say(json.joke)
}
}
}
实例:
const say = function(text) {
out.innerHTML = text
return new Promise((resolve) => {
const utterance = new SpeechSynthesisUtterance(text);
utterance.onend = resolve;
window.speechSynthesis.speak(utterance);
});
};
const delay = t => new Promise(resolve => setTimeout(resolve, t))
const out = document.querySelector("#output");
const stop = document.querySelector("#stop")
stop.addEventListener("click", () => running = false)
let running = true
async function run() {
while (running) {
var res = await fetch("https://v2.jokeapi.dev/joke/Any")
var json = await res.json();
//console.log(json)
if (json.type == "twopart") {
await say(json.setup);
await delay(1000);
await say(json.delivery);
} else if (json.type == "single") {
await say(json.joke)
}
}
}
run()
<div id="output">
</div>
<button id="stop">
Stop
</button>