2016-09-24 43 views
1

如何将此算法编码为JavaScript中的承诺?Javascript:承诺等待条件或尝试次数后中止

// condition: some situation that is not true 
// interval: period to wait before trying again 
// retriesAllowed: maximum number of retries to make before aborting 
// retriesMade: number of retries made so far 
while() { 
    if (condition) return true; // indicates success 
    if (retriesMade < retriesAllowed) return false; // or throw an exception 
    ++retriesMade; 
    wait(interval); 
} 

这是不行的,因为它实际上并没有在移动之前等待检查,以解决为true或false:

var check =() => { 
    if (condition) return true; // indicates success 
    if (retriesMade < retriesAllowed) return false; // or throw an exception 
    ++retriesMade; 
    setTimeout(check,interval) 
} 
check(); 
+0

[https://github.com/kriskowal/q](https://github.com/kriskowal/q) –

+1

@CodeSpirit [本地承诺](https://developer.mozilla.org/ EN-US /文档/网络/的JavaScript /参考/ Global_Objects /无极)。 –

+0

到目前为止你能弄清楚什么?你能分享你尝试过的一个片段吗? (Stack Overflow不是一个代码编写服务,这里有一个期望,你首先已经投入了一些你自己的努力。) –

回答

2

这是不行的,因为它实际上并没有等待检查移动之前解析为真或假。那

一部分可能是故障/退出条件似乎是反转,所以它会在第一轮检查condition后可能永远退出:

// retriesMade starts at 0, which is likely already less-than retriesAllowed 
if (retriesMade < retriesAllowed) return false; 

// probably should be 
if (retriesMade >= retriesAllowed) return false; 

除此之外, ,缺乏等待是通过异步操作设计的,例如setTimeout()等待给定的延迟间隔。周围的代码将始终继续执行,无需等待结果。

而不是期望他们等待,你需要建立一个方法,当过程已经实际完成并通过该信息进行通知。承诺是一个选择。

旁注:行为和其他选项的详尽的解释在“How do I return the response from an asynchronous call?

与他们提供的,取代使用returnthrow的,他们提供resolve()reject()函数信号成功或失败时分别被调用。他们的.then().catch()方法可用于设置延续。

var tries = new Promise((resolve, reject) => { 
    var retriesMade = 0; 
    var interval = 1000; 

    var check =() => { 
     if (condition) { resolve(); } 
     if (retriesMade >= retriesAllowed) { reject(); } 
     ++retriesMade; 
     setTimeout(check, interval); 
    }); 

    check(); 
}); 

tries.then(
    () => console.log('success'), 
    () => console.log('failure') 
); 

同样,更彻底地使用承诺,含有一个函数(untilLimited)迭代以及允许条件(exitUpon)是异步的,如果需要的话的替代版本。

function delay(milliseconds) { 
    return new Promise(function (resolve) { 
    setTimeout(resolve, milliseconds); 
    }); 
} 

function untilLimited(limit, waitTime, exitUpon) { 
    return Promise.resolve() 
    .then(exitUpon) 
    .then(result => { 
     if (result) return true; 
     if (!(--limit > 0)) return Promise.reject('Limit exceeded.'); 
     return delay(waitTime) 
     .then(() => untilLimited(limit, waitTime, exitUpon)) 
    }); 
} 

untilLimited(5, 500,() => false /* condition */) 
    .then(
    (result) => console.log('success', result), 
    (result) => console.log('failure', result) 
); 
+0

你不应该在你的回调代码中包装一个'新的Promise',你应该实际使用* promises – Bergi

+0

@Bergi你能详细说明你的意思吗?我不知道一个原生的,基于Promise的'setTimeout()'等价物,所以看起来有些包装是不可避免的。尽管如此,它可能会被最小化。 –

+0

是的,但是你应该只包装* setTimeout',而不是其他任何东西,然后使用承诺的算法。 – Bergi

0

您可以使用q库(或$q在angular)返回一个延迟对象,并在后台运行该时间间隔,如果经过几次尝试,condition不满足,则拒绝承诺。

Example for Angular

+0

这不是一个好的答案。 Angular在这里甚至没有相关 –

+0

您可以使用q库而不使用角度。 $ q只是一个角度的包装。核心库工作原理相同 – eavidan