当前,我正在尝试使重复的Ajax-Calls动态化,以便使我的代码更易于管理。这样做时,我有时会需要动态数据属性和-values。总是只有一个数据值发生变化,其他参数保持不变。这样我就可以轻松实现承诺。
这是我用作这些Ajax-Call模板的示例:
var prepareAjax = {
iterateValues: [1230,1280,4000,9000],
ajaxOptions: [{
timeout: 10000,
type: "GET",
data: `{
param1: item,
param2: obj.sessionId,
param3: 1
}`,
url: 'https://someurl.tld/target'
}],
sessionId: '<somestring>'
};
在此对象之后,我正在调用一个函数,该函数应像这样从对象中提取ajaxOptions
:
function fetchChain(obj)=>{
var ajaxPromises = [], tempObj;
obj.iterateValues.map((item, index)=> {
tempObj = obj.ajaxOptions[0];
tempObj.data = eval('('+tempObj.data+')');
ajaxPromises.push(new Promise(
(resolve, reject)=>{
namespace.fetchData(tempObj);
}
);
}
}
我在这里所做的是为每个ìterateValue
创建一个Promise和Ajax-Call。然后,我使用eval(是,是邪恶)来解析当前上下文(fetchChain
)的变量并将其提供给fetchData
。这些函数是在名称空间中执行的,因此在示例中以namespace.fetchChain(prepareAjax)
进行调用。
问题
此示例仅适用于一次迭代,因为即使我仅评估/修改obj
,eval似乎也会永久更改tempObj
,但显然我想在每次迭代中重用模板。需要解析的唯一值是item
,参数保持不变。
我也知道new Function()
是eval
的更好选择,但我也无法使它工作。对我而言,更奇怪的是,该函数以前在不使用fetchChain()
之类的准备函数而直接在Ajax-Call内部评估数据属性时就可以工作了。即使在阅读了关于SO的几个答案之后,我仍然停留在这一点上。
为完整起见,这是fetchData函数:
function fetchData(obj)=>{
// single ajax-calls should use a delay of 0
obj.timeout = ((obj.timeout) ? obj.timeout : 10000),
obj.retries = ((obj.retries) ? obj.retries : 5),
obj.delay = ((obj.delay) ? obj.delay : 1000),
obj.type = ((obj.type) ? obj.type : "GET"),
obj.cnt = ((obj.cnt) ? obj.cnt++ : 0);
var sumDelay = obj.delay*(obj.cnt+1);
setTimeout(()=>{
return new Promise((resolve, reject)=>{
return $.ajax(obj)
.done((response)=>{
return resolve(response);
}).fail((error)=>{
if(obj.cnt++ >= obj.retries){
return resolve('Error');
}
fun.fetchData(obj);
}).always((xd)=>{
})
})
}, sumDelay)
}
解决方案
我正在考虑的解决方案是在将对象提供给fetchChain()
之前准备对象。或者更明确地说:在创建prepareAjax
的上下文中。显然,我希望直接在fetchChain()
内部处理此过程。
错误
当如上所述执行fetchChain
时,我在eval的第二次迭代中收到错误Unexpected Identifier
。 ([对象对象])调试时可以看到obj
也更改了data
的值。
答案 0 :(得分:1)
为什么不做一些动态获取该obj的事情?
例如:
const iterateValues = [1230,1280,4000,9000];
const getAjaxOpts = value => {
return {
ajaxOptions: [{
timeout: 10000,
type: "GET",
data: /* apply data here from value */
url: 'https://someurl.tld/target'
}],
sessionId: '<somestring>'
};
};
并执行类似的迭代:
const mapped = iterateValues.map(x => getAjaxOpts(x));
// do your promise things afterwards
答案 1 :(得分:0)
在尝试摆脱eval()
时,我遇到了与eval相同的问题→原始对象也总是被更改,这样在执行结束时所有动态参数都相同。
事实证明,我对'='-运算符在对象上的工作方式有基本的误解。这些对象不会被克隆,而是被引用。由于已经有更好的解释性答案(取决于js中的克隆对象),我只链接到一个答案here。
因此,当我在eval
上使用tempObj
时,实际上会发生的不仅是将tempObj
的模板字符串(数据属性)变成一个对象,而且它引用的obj
的模板字符串。
解决此问题的简便方法,该方法似乎很常用:
var A = JSON.parse(JSON.stringify(obj));
其他人,由于他们的工作方式而对我不起作用:
var A = Object.create(obj);
var A = Object.assign({},obj);
还有更多更好的解决方案,但请看一下上面的链接。
由于我一直在寻求使用eval
的解决方案,因此我在此举一个实际可行的示例,它甚至支持多个动态参数和参数值。
function chainAjax(){
var ajaxPromises = [], tempObj,
iterateProps = Object.getOwnPropertyNames(obj.iterateValues[0])
obj.iterateValues[0][iterateProps].map((item, index)=> {
tempObj = JSON.parse(JSON.stringify(obj.ajaxOptions[0]));
tempObj.data = eval('('+tempObj.data+')');
ajaxPromises.push(new Promise(
(resolve, reject)=>{
fetchData(tempObj).then(...)
}
))
})
return Promise.all(ajaxPromises);
}
作为模板,我将使用以下内容:
var prepareAjax = {
iterateValues: [{
appid: [1230,1280,4000,9000]
}],
ajaxOptions: [{
timeout: 10000,
type: "GET",
data: `{
appid: obj.iterateValues[0].appid[index],
sessionid: '<somestring>',
wizard_ajax: 1
}`,
url: 'https://someurl.tld/target'
}]
}
最后但并非最不重要的示例,它不带评估功能:
function fetchChain(obj)=>{
var ajaxPromises = tempArray = [], tempObject,
iterateProps = Object.getOwnPropertyNames(obj.iterateValues[0]);
// Prepare Data-Objects and resolve dynamic vars
obj.iterateValues[0][iterateProps[0]].map((item, index)=> {
tempObject = JSON.parse(JSON.stringify(obj.ajaxOptions[0])); // clone trick
iterateProps.map(keyname =>
tempObject.data[keyname] = obj.iterateValues[0][keyname][index]
)
tempArray.push(tempObject);
});
tempArray.map((item, index)=> {;
ajaxPromises.push(
fun.fetchData(item).then((response)=>{
return response;
});
)
})
return Promise.all(ajaxPromises);
}
和一个稍微不同的模板:
var prepareAjax = {
iterateValues: [{ // matching property-names
appid: [1230,1280,4000,9000]//═══════╗
}], // ║
ajaxOptions: [{ // ║
data: { // ║
appid: '',//<════════════════════╝
sessionid: '<somestring>',
wizard_ajax: 1
},
url: 'https://somedomain.tld/target'
}]
}