Javascript 无法将间隔设置为最长2分钟,或直到使用角度传感器满足条件
这里我的场景是,我有两个apiapiOne和apiTwo,当我调用apiOne时,应该给出响应,如果响应成功,那么我必须将此报告作为参数发送到apiTwo,然后apiTwo将给出另一个响应,我可能会得到如“已创建”、“正在进行”。问题就在这里Javascript 无法将间隔设置为最长2分钟,或直到使用角度传感器满足条件,javascript,angular,ionic-framework,Javascript,Angular,Ionic Framework,这里我的场景是,我有两个apiapiOne和apiTwo,当我调用apiOne时,应该给出响应,如果响应成功,那么我必须将此报告作为参数发送到apiTwo,然后apiTwo将给出另一个响应,我可能会得到如“已创建”、“正在进行”。问题就在这里 如何使用间隔每3秒调用APITOW,直到得到“正在进行”的响应,如果没有得到如上所述的响应,则需要轮询APITOW,直到最长2分钟,然后取消调用。如果我得到的响应为正在进行中,则我需要停止间隔或最多2分钟取消间隔或子描述 我已经用嵌套的方式编写了代码,但
initiate() {
this.showProgress = true;
const data = {
id: this.id,
info: this.Values.info,
};
// First Api call
this.userServ.start(data).subscribe(res => {
this.Ids = res['Id'];
if (this.Ids) {
// Second Api call
this.Service.getStatus(this.Ids).subscribe(resp => {
if (resp) {
this.Status = res['Status'];
// if resp is In_Progress
if (this.Status === 'In_Progress') {
this.Start();
} else {
// if resp is not In_Progress then i get the response i am calling the api
this.intervalTimer = interval(3000).subscribe(x => {
this.Service.Status(this.Ids).subscribe(ress => {
this.Status = ress['Status'];
if (this.Status === 'In_Progress') {
this.delayStart();
this.intervalTimer.unsubscribe();
}
});
});
}
}
}, err => {
console.log(err);
});
}
}, error => {
console.log(error);
});
}
你可以考虑使用下面的方法
然后,我们创建一个主题
,以帮助跟踪操作的进度。我使用BehaviorSubject将显示进度的初始值设置为true
我们将使用currentStatus$
存储当前状态是“正在进行”还是“已创建”
停止$
和启动
将控制我们的可观察流
你可以看看下面的帖子
接下来我们定义interval=500;//将3s和maxTrialTime=6000更改为3000;//更改为120000,持续2分钟
然后,我们使用timer
操作符定义一个timer$
可观察的。运算符用于以固定间隔生成值流
我们将延迟设置为0
,将间隔设置为先前创建的interval
属性
然后,我们将点击进入可观察的流。tap
操作符允许我们在不改变可观察流的情况下执行操作
在我们的tap操作符中,我们检查是否已达到最大时间,如果已达到,则调用stoppedSubject$
上的下一个函数。我们将流输送到takeUntil(this.stopped$)
停止流,并repeatWhen(()=>this.started$)
重新启动流
timer$ = timer(0, this.interval).pipe(
tap((i) => {
if(this.maxTrialTime/this.interval < i) { this.stoppedSubject$.next()}
}),
takeUntil(this.stopped$),
repeatWhen(() => this.started$)
)
现在,我们终于将timer$
和apiTwoCall$
与mergeMap
操作符trialCallsToApiTwo$=this.timer$.pipe(mergeMap(()=>this.apiTwoCall$)结合起来了。
在HTML中,我们可以使用async
管道来避免担心取消订阅
{{ trialCallsToApiTwo$ | async }}
我将使用rxjs中的展开
,它将传递源可观测的结果,但也让您根据结果的内容进行操作
此外,尽可能避免嵌套调用subscribe
。考虑下面的示例代码:
this.userServ.start(data).pipe(
// use switchMap to not have 'nested' subscribe-calls
switchMap((result) => {
if (result['Id']) {
// if there is an ID, ask for the status
return this.Service.getStatus(result['Id']).pipe(
// use the expand operator to do additional processing, if necessary
expand((response) => response['Status'] === 'In_Progress'
// if the status is 'In_Progress', don't repeat the API call
? EMPTY
// otherwise, re-run the API call
: this.Service.getStatus(result['Id']).pipe(
// don't re-run the query immediately, instead, wait for 3s
delay(3000)
)
),
// Stop processing when a condition is met, in this case, 60s pass
takeUntil(timer(60000).pipe(
tap(() => {
// handle the timeout here
})
))
);
} else {
// if there is no ID, complete the observable and do nothing
return EMPTY;
}
}),
/**
* Since expand doesn't filter anything away, we don't want results that
* don't have the status 'In_Progress' to go further down for processing
*/
filter((response) => response['Status'] === 'In_Progress')
).subscribe(
(response) => {
this.Start();
}, (error) => {
console.log(error)
}
);
我认为在设定的时间间隔后调用api会给应用程序和网络带来很大的开销。这对你有帮助吗@ChetanBansal不,这是一个不同的例子,我的情况不同。可能需要解释一下,因为你正在用观测值轰炸OP。@Robinijkhof好的,会用解释更新我的答案的
showProgressSubject$ = new BehaviorSubject(true);
showProgressAction$ = this.showProgressSubject$.asObservable();
currentStatus$ = this.currentStatusSubject$.asObservable()
stoppedSubject$ = new Subject();
stopped$ = this.stoppedSubject$.asObservable();
startedSubject$ = new Subject();
started$ = this.startedSubject$.asObservable();
timer$ = timer(0, this.interval).pipe(
tap((i) => {
if(this.maxTrialTime/this.interval < i) { this.stoppedSubject$.next()}
}),
takeUntil(this.stopped$),
repeatWhen(() => this.started$)
)
apiOneCall$ = this.userServ.start(this.data);
apiTwoCall$ = this.apiOneCall$.pipe(
switchMap(({Id}) => Id ? this.Service.getStatus(Id): throwError('No Id')),
tap((res) => this.currentStatusSubject$.next(res)),
tap(res => console.log({res})),
tap((res) => {if(res === 'created') {this.stoppedSubject$.next()}})
)
{{ trialCallsToApiTwo$ | async }}
this.userServ.start(data).pipe(
// use switchMap to not have 'nested' subscribe-calls
switchMap((result) => {
if (result['Id']) {
// if there is an ID, ask for the status
return this.Service.getStatus(result['Id']).pipe(
// use the expand operator to do additional processing, if necessary
expand((response) => response['Status'] === 'In_Progress'
// if the status is 'In_Progress', don't repeat the API call
? EMPTY
// otherwise, re-run the API call
: this.Service.getStatus(result['Id']).pipe(
// don't re-run the query immediately, instead, wait for 3s
delay(3000)
)
),
// Stop processing when a condition is met, in this case, 60s pass
takeUntil(timer(60000).pipe(
tap(() => {
// handle the timeout here
})
))
);
} else {
// if there is no ID, complete the observable and do nothing
return EMPTY;
}
}),
/**
* Since expand doesn't filter anything away, we don't want results that
* don't have the status 'In_Progress' to go further down for processing
*/
filter((response) => response['Status'] === 'In_Progress')
).subscribe(
(response) => {
this.Start();
}, (error) => {
console.log(error)
}
);