Javascript 如果未解决,如何取消上次承诺?
假设我有一个搜索函数来进行HTTP调用。 每个电话可能需要不同的时间。 所以我需要取消最后一个HTTP请求,只等待最后一个调用Javascript 如果未解决,如何取消上次承诺?,javascript,promise,cancellation,Javascript,Promise,Cancellation,假设我有一个搜索函数来进行HTTP调用。 每个电话可能需要不同的时间。 所以我需要取消最后一个HTTP请求,只等待最后一个调用 async function search(timeout){ const data = await promise(timeout) return data; } // the promise function is only for visualizing an http call function promise(timeout){ retu
async function search(timeout){
const data = await promise(timeout)
return data;
}
// the promise function is only for visualizing an http call
function promise(timeout){
return new Promise(resolve,reject){
setTimeout(function(){
resolve()
},timeout)
}
}
search(200)
.then(function(){console.log('search1 resolved')})
.catch(function() {console.log('search1 rejected')})
search(2000)
.then(function(){console.log('search2 resolved')})
.catch(function(){console.log('search2 rejected')})
search(1000)
.then(function(){console.log('search3 resolved')})
.catch(function(){console.log('search3 rejected')})
需要查看“search1已解决”“search2已拒绝”“search3已解决”
如何实现此方案?您可以定义一个工厂函数,用请求的取消行为封装您的
search()
方法。请注意,在这种情况下,有必要在pending
集合中保留对每个reject()
函数的引用,以实现提前取消
可取消功能(fn){
const pending=新集合();
返回函数(){
返回新承诺(异步(解析、拒绝)=>{
让我们安定下来;
让结果;
试一试{
待定。添加(拒绝);
解决=决心;
result=wait Promise.resolve(fn.apply(这个,参数));
}捕获(错误){
解决=拒绝;
结果=错误;
}
//如果本承诺未被取消
如果(待定,有(拒绝)){
//取消在此之前拨打的电话中的待定承诺
for(挂起的常量取消){
待定。删除(取消);
如果(取消!==拒绝){
取消();
}否则{
打破
}
}
解决(结果);
}
});
};
}
//内部API函数
函数searchImpl(超时){
返回新承诺((解决、拒绝)=>{
setTimeout(解析,超时);
});
}
//将内部API函数传递给Cancelable()
//并将返回值用作外部API函数
const search=可取消(searchImpl);
搜索(200)。然后(()=>{
console.log('search1已解决');
}, () => {
console.log(“search1被拒绝”);
});
搜索(2000)。然后(()=>{
console.log('search2已解决');
}, () => {
console.log(“search2被拒绝”);
});
搜索(1000)。然后(()=>{
console.log('search3已解决');
}, () => {
console.log(“search3被拒绝”);
});
搜索(500)。然后(函数(){
console.log('search4已解决');
}, () => {
console.log('search4已拒绝');
});代码>承诺本身是不可取消的,但在有限的意义上会被取消,因为它会导致承诺被拒绝
考虑到这一点,可以通过少量的细化和希望取消的承诺返回功能来实现取消
function makeCancellable(fn) {
var reject_; // cache for the latest `reject` executable
return function(...params) {
if(reject_) reject_(new Error('_cancelled_')); // If previous reject_ exists, cancel it.
// Note, this has an effect only if the previous race is still pending.
let canceller = new Promise((resolve, reject) => { // create canceller promise
reject_ = reject; // cache the canceller's `reject` executable
});
return Promise.race([canceller, fn.apply(null, params)]); // now race the promise of interest against the canceller
}
}
假设您的http调用函数名为httpRequest
(promise
令人困惑):
现在,每次调用search()
如有必要,catch回调可以测试err.message=='\u cancelled.
,以区分取消和其他拒绝原因。与PatrickRoberts的答案类似,我建议使用映射来维护未决承诺的列表
但是,我不会在promise构造函数之外维护对reject
回调的引用。我建议放弃拒绝过时承诺的想法。相反,忽略它。将其包装在一个承诺中,该承诺永远不会解析或拒绝,但仍然是一个永远不会改变状态的死承诺对象。事实上,这种无声的承诺在你需要的每一个场合都是一样的
下面是它的样子:
constdelay=(超时,数据)=>newpromise(解析=>setTimeout(()=>resolve(数据),超时));
const godot=新承诺(()=>null);
const search=(函数(){//闭包。。。
const requests=new Map;//…以便共享变量
设id=1;
返回异步函数搜索(){
让持续时间=Math.floor(Math.random()*2000);
let request=delay(持续时间,“data”+id);//这将是一个HTTP请求
requests.set(request,id++);
让数据=等待请求;
如果(!requests.has(request))返回godot;//永不解析。。。
for(让[pendingRequest,pendingId]请求){
如果(pendingRequest==请求)中断;
请求。删除(待处理请求);
//只是为了演示,我们输出了一些东西。
//在真实场景中不需要:
log(“忽略搜索”+pendingId);
}
请求。删除(请求);
返回数据;
}
})();
const reportSuccess=data=>console.log(“搜索已用“+数据解决”);
const reportError=err=>console.log('搜索被拒绝,带有'+err');
//定期生成搜索。
//在真实场景中,这可能是对关键事件的响应。
//每个承诺都会以随机的持续时间进行解析。
setInterval(()=>search().then(reportSuccess).catch(reportError),100代码>如果您有多个承诺链接在一起-当其中一个承诺被拒绝时,链将停止。你没有把它们链接起来,所以它们每次都会执行。Aksi回答了这个问题,但你应该转向异步,等待它变得更简单。这不是我想要的场景。我只需要取消promise函数的最后一个调用如果尚未解决promise函数只需像API一样可视化异步调用我只希望最后一个承诺得到解决或任何其他在1000毫秒之前解决的承诺你的承诺构造应该是新承诺((解决,拒绝)=>…)
,记录promise2解决了什么问题?
?您的问题不明确。如果在收到新请求时确实取消了最后一个承诺,那么您的代码示例应该生成“search1拒绝”,而不是“search1已解决”,因为search
的第二次调用应该将以前的承诺标识为未解决。但是,如果您想给ever promise首先解析的优先级,那么输出应该是“search1 resolved”,另外两个被拒绝。Pl
const search = makeCancellable(httpRequest);
// Search 1: straightforward - nothing to cancel - httpRequest(200) is called
search(200)
.then(function() { console.log('search1 resolved') })
.catch(function(err) { console.log('search3 rejected', err) });
// Search 2: search 1 is cancelled and its catch callback fires - httpRequest(2000) is called
search(2000)
.then(function() { console.log('search2 resolved') })
.catch(function(err) { console.log('search3 rejected', err) });
// Search 3: search 2 is cancelled and its catch callback fires - httpRequest(1000) is called
search(1000)
.then(function() { console.log('search3 resolved') })
.catch(function(err) { console.log('search3 rejected', err) });