项目实战问题总结:循环发送请求
循环发送请求,除非必要,否则最好还是不要这么干,尤其是前后端分离项目,应当尽量避免发送多条请求,其实大部分场景下都可以找到可替代的方案。
但不排除一定要这么干的时候,这个需求,可以使用Promise,利用递归思想实现链式发送、处理请求。
我的需求
一个可以多选删除的列表,如果被删除项被一些Service调用,要提示无法删除。
正常思路应该是:把待删除项的id放进数组发给后端,后端返回判断结果,然后前端根据判断结果提示用户。
因为某些原因,实际思路为:前端遍历待删除项的id,依次发送能否删除的请求,如果有一条不能删除,那么所有项都不可删除,根据后端响应提示用户。
所以就用到了野路子——递归实现循环发送请求。
代码
private checkReference = (//递归方法在此
deleteIdList: string[],
previousItemReference?: boolean,//上一层递归的数据。
): Promise<any> => {
const deleteId = deleteIdList.pop()!;
return deleteId
? getExecutionScheduleReference(deleteId)
.then((data) => {
const hasReference = data.length > 0 || previousItemReference;
return this.checkReference(deleteIdList, hasReference);//在此递归
})
: Promise.resolve(previousItemReference);//下文详细介绍Promise.resolve()
}
private deleteExecutionSchedule = (): Promise<any> => {
const deleteItemId: string[] = this.props.selectionDetails!.map((item) => item.id);
//待删除ID的Array
const deleteCopy = [...deleteItemId];
//复制一下,因为在this.checkReference()执行完之后,deleteItemId就成空数组了。
// reference check at here. --start
return this.checkReference(deleteItemId, false)
.then((hasReference) => {
if (hasReference) {
//不能删除,提示用户
} else {
deleteExecutionSchedule(deleteCopy)
.then(() => {
//删除成功回调
})
.catch(() => {
//删除失败回调
});
}
});
// reference check at here. --end
}
细节
递归实现的重点,就在于利用Promise的链式调用思路,Promise的构造函数接收参数:一个executor,该executor接收两个函数做参数:resolve,reject,便于理解可以直接简单认为resolve是成功回调,reject是失败回调(其实这两个函数意味着将Promise从pendding状态改变为fulfilled或rejected状态)。
const promise = new Promise((resolve,reject)=>{
//异步操作
})
Promise.then(),可以理解为触发Promise,使之执行executor,then()接受两个函数:onFulfilled和onRejected。这两个函数是执行executor,状态变成fulfilled或rejected后调用的函数,实例化Promise时executor中的只是参数,而then()方法中是定义好的函数,then()提供的resolve函数会在executor中被调用。
如果 then 中的回调函数:
- 返回了一个值,那么 then 返回的 Promise 将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值。
- 没有返回任何值,那么 then 返回的 Promise 将会成为接受状态,并且该接受状态的回调函数的参数值为 undefined。
- 抛出一个错误,那么 then 返回的 Promise 将会成为拒绝状态,并且将抛出的错误作为拒绝状态的回调函数的参数值。
- 返回一个已经是接受状态的 Promise,那么 then 返回的 Promise 也会成为接受状态,并且将那个 Promise 的接受状态的回调函数的参数值作为该被返回的Promise的接受状态回调函数的参数值。
- 返回一个已经是拒绝状态的 Promise,那么 then 返回的 Promise 也会成为拒绝状态,并且将那个 Promise 的拒绝状态的回调函数的参数值作为该被返回的Promise的拒绝状态回调函数的参数值。
- 返回一个未定状态(pending)的 Promise,那么 then 返回 Promise 的状态也是未定的,并且它的终态与那个 Promise 的终态相同;同时,它变为终态时调用的回调函数参数与那个 Promise 变为终态时的回调函数的参数是相同的。
引用自——MDN-Promise介绍
promise.then((data)=>{
//操作data
})
而Promise.resolve(data)可以直接跳过执行,返回一个状态为fulfilled的Promise,data就是resolve回调函数的参数。(简单理解为此时可以用then((data)=>{ })得到data)。
如代码所示,递归的使用,使得下一个请求总是在当前请求的then()方法中,如此递归下去,直到达到临界条件——待删除id的个数为0,递归结束,此时就构造了一条Promise调用链。
形如:
new Promise(()=>{
//异步操作
}).then(()=>{
new Promise(()=>{
//异步操作
}).then(()=>{
new Promise(()=>{
//异步操作
}).then(()=>{
//递归至达到临界条件
})
})
})