我希望这段代码能说明一切第一个按钮启动异步命令(在此示例中为setTimeout),第二个按钮允许在旅途中停止其执行。
[除了我的代码中没有像我想象的那样,而且我承认,我仍然很难满足诺言...。
目前我不明白为什么setTimeout没有效果?
我(仍然)想念什么?
(function(messageBox)
{
const texBox = document.getElementById('message-box')
;
messageBox.txt = txt => texBox.textContent = txt
messageBox.add = txt => texBox.textContent += '\n'+txt
}
(window.messageBox=window.messageBox || {}));
function timer()
{
let status = 'none' // inUse
, obj = document.createElement('b')
, ref = null
, msTime = 0
;
const sleep =_=> new Promise(res => ref=setTimeout(res, ms))
, cancel =_=> new Promise(res => {
obj.onclick =_=> {
if (status==='inUse') {
clearTimeout(ref)
res()
} } })
async function start( ms ) {
if (status==='none') {
msTime = ms
status = 'inUse'
await Promise.race([sleep,cancel])
status = 'none'
}
}
function stop() { if (status==='inUse') obj.click() }
return( { start, stop} )
}
const btStart = document.getElementById('bt-start')
, btAbort = document.getElementById('bt-abort')
, OnDelay = timer()
;
btStart.onclick=_=>
{
messageBox.txt('Start waitting 5 seconds...')
OnDelay.start(5000)
messageBox.add('finish waitting :)')
}
btAbort.onclick=_=>
{
OnDelay.stop()
messageBox.add('...abort !')
}
#message-box {
margin: 1em;
border: 1px solid lightskyblue;
width: 20em;
height: 10em;
}
<button id="bt-start">wait 5s</button>
<button id="bt-abort">abort</button>
<pre id="message-box">message...</pre>
这个想法是:2个选择a)单击按钮wait 5s
=> messageBox将立即显示Start waiting 5 seconds...
和5秒后,程序将添加finish wait:)
messageBox =
[开始等待5秒钟...完成等待:)
(我不希望它起作用)
b)单击按钮wait 5s
=> messageBox = Start waiting 5 seconds...
(此时与= a =相同)
然后单击之前按钮abort
的5秒结束=> messageBox =
[开始等待5秒钟......中止!完成等待:)
在5秒钟之前(它也无法如我所愿)
我在下面添加了一些简单的代码,它们可以模拟您所需的执行,并有助于解决您的查询。
(() => {
const messageBox = document.getElementById('message-box');
const btStart = document.getElementById('bt-start');
const btAbort = document.getElementById('bt-abort');
const interval = 5000;
let objTimeout = null;
btStart.onclick = () => {
messageBox.textContent += `\n [-] start waiting ${interval} ms...`;
objTimeout = setTimeout(()=>{
messageBox.textContent += `\n [-] message after ${interval} ms`;
},interval)
}
btAbort.onclick = () => {
if(objTimeout){
clearTimeout(objTimeout);
messageBox.textContent += `\n [x] printing aborted`;
messageBox.textContent += `\n [x] finish waiting`;
}
}
})();
#message-box {
margin: 1em;
border: 1px solid lightskyblue;
width: 30em;
height: 10em;
}
<button id="bt-start">wait 5s</button>
<button id="bt-abort">abort</button>
<pre id="message-box">waiting for message...</pre>
================================================ ==================我已在下面的摘要中发布了承诺。仅当您想要同步代码或防止竞争条件或想要逐行执行语句时,才需要执行相同的promise。希望它能对问题有所启发并帮助解决。
(() => {
const messageBox = document.getElementById('message-box');
const btStart = document.getElementById('bt-start');
const btAbort = document.getElementById('bt-abort');
const interval = 5000;
let objTimeout = null;
let objPromise = null;
btStart.onclick = () => {
return new Promise((resolve, reject) => {
objTimeout = setTimeout(() => {
objPromise = Promise.resolve().then(() => {
messageBox.textContent += `\n [-] start waitting ${interval} seconds...`;
}).then(() => {
messageBox.textContent += `\n [-] message after ${interval} ms`;
}, interval).then(() => {
messageBox.textContent += `\n [-] printing finished`;
resolve();
});
}, interval);
});
}
btAbort.onclick = () => {
if(objTimeout !== null){
Promise.reject(new Error("promise aborted"));
clearTimeout(objTimeout);
messageBox.textContent += `\n [x] printing aborted`;
messageBox.textContent += `\n [x] finish waiting`;
objTimeout= null;
}
}
})();
#message-box {
margin: 1em;
border: 1px solid lightskyblue;
width: 30em;
height: 10em;
}
<button id="bt-start">wait 5s</button>
<button id="bt-abort">abort</button>
<pre id="message-box">waiting for message...</pre>
我认为您正在考虑问题。
您需要的是one Promise及其通常的.then
,.reject
和.finally()
。不需要.race
。
此外,您还可以将所有这些操作包装到一个类中,作为一种更干净,可重用的方法:
const messageBox = document.getElementById('message-box');
const btStart = document.getElementById('bt-start');
const btAbort = document.getElementById('bt-abort');
class Countdown {
constructor(onStart, onEnd, onAbort){
this.timeout = null;
this.handleCatch = onAbort;
this.handleFinally = onEnd;
this.starter = (res, rej) => {
onStart();
this.timeout = setTimeout(res, 5000);
// Pass the `reject` function to a property to be used later
this.aborter = rej;
};
}
async start(){
try {
// Only one `Promise` is needed.
this.main = await new Promise(this.starter);
} catch(e){
/* This will run on abort */
// Stop the timeout
clearTimeout(this.timeout);
// Reset the property to make sure `abort` can only be run once for each valid timeout.
this.aborter = null;
this.handleCatch();
} finally {
/* This will run after everything ends */
this.handleFinally();
}
}
abort(){
if (typeof this.aborter === 'function'){
// Use the `reject` that is passed to this property earlier.
this.aborter();
}
}
}
const countdown = new Countdown(
// Run when countdown is started. See `onStart` in the class consturctor.
() => messageBox.txt('Start waiting 5 seconds...'),
// Run when countdown is ended. See `onEnd` in the class consturctor.
() => messageBox.add('finish waiting :)'),
// Run when countdown is aborted. See `onAbort` in the class consturctor.
() => messageBox.add('...abort!')
)
messageBox.txt = text => messageBox.textContent = text;
messageBox.add = text => messageBox.textContent += '\n' + text;
btStart.addEventListener('click', countdown.start.bind(countdown));
btAbort.addEventListener('click', countdown.abort.bind(countdown));
#message-box {
margin: 1em;
border: 1px solid lightskyblue;
width: 20em;
height: 10em;
}
<button id="bt-start">wait 5s</button>
<button id="bt-abort">abort</button>
<pre id="message-box">message...</pre>
这样,不仅代码是干净的,而且可以在代码中的任何地方重复使用倒数计时。
您要做的就是告诉实例要执行的操作onStart
,onEnd
和onAbort
。
(function(messageBox) {
const texBox = document.getElementById('message-box');
messageBox.txt = txt => texBox.textContent = txt
messageBox.add = txt => texBox.textContent += '\n' + txt
}
(window.messageBox = window.messageBox || {}));
function timer() {
let timerID, rejectPromise;
function start(nMS) {
return new Promise((resolve, reject) => {
timerID = setTimeout(_ => {
timerID = undefined;
resolve();
}, nMS);
rejectPromise = reject;
});
}
function stop() {
timerID && clearTimeout(timerID);
timerID = undefined;
rejectPromise();
}
return ({
start,
stop
})
}
const btStart = document.getElementById('bt-start'),
btAbort = document.getElementById('bt-abort'),
OnDelay = timer();
btStart.onclick = async _ => {
messageBox.txt('Start waitting 5 seconds...')
try {
await OnDelay.start(5000);
} catch (_) {}
messageBox.add('finish waitting :)')
}
btAbort.onclick = _ => {
OnDelay.stop()
messageBox.add('...abort !')
}
#message-box {
margin: 1em;
border: 1px solid lightskyblue;
width: 20em;
height: 10em;
}
<button id="bt-start">wait 5s</button>
<button id="bt-abort">abort</button>
<pre id="message-box">message...</pre>
注意:要等待5秒,然后then做某事,您必须
p
,5秒钟后由setTimeout
解决,另一行说p.then(function() { doSomething() })
await
进行上述(1)中的保证。由于即使您拒绝了诺言,您也希望执行相同的操作,所以我在try... catch
上添加了await
。否则将引发错误,并且await
下面的代码将不会继续。
在您的原始代码中,您调用了OnDelay.start(5000)
,它将一直运行到await
行,以等待该诺言得到解决,并且控件返回到messageBox.add('finish waitting :)')
的下一行,并且它将立即显示。它不像同步程序,您可以在其中“睡眠” 5秒钟。仅当您在异步函数中完成所有操作并且您在5秒钟内解决await promise
然后执行某项操作,或者使用诺言然后在5秒内解决并将其设置为promise.then(doSomething)
时,才有可能。 >
由于即使希望被拒绝,您也希望执行相同的操作,所以您将使用finally
而不是then
。
(function(messageBox) { const texBox = document.getElementById('message-box'); messageBox.txt = txt => texBox.textContent = txt messageBox.add = txt => texBox.textContent += '\n' + txt } (window.messageBox = window.messageBox || {})); function timer() { let timerID, rejectPromise; function start(nMS) { return new Promise((resolve, reject) => { timerID = setTimeout(_ => { timerID = undefined; resolve(); }, nMS); rejectPromise = reject; }); } function stop() { timerID && clearTimeout(timerID); timerID = undefined; rejectPromise(); } return ({ start, stop }) } const btStart = document.getElementById('bt-start'), btAbort = document.getElementById('bt-abort'), OnDelay = timer(); btStart.onclick = _ => { messageBox.txt('Start waitting 5 seconds...') OnDelay.start(5000).finally(_ => messageBox.add('finish waitting :)')); } btAbort.onclick = _ => { OnDelay.stop() messageBox.add('...abort !') }
#message-box { margin: 1em; border: 1px solid lightskyblue; width: 20em; height: 10em; }
<button id="bt-start">wait 5s</button> <button id="bt-abort">abort</button> <pre id="message-box">message...</pre>