0

目前我正在尝试使重复的 Ajax-Calls 动态化,以便我的代码更易于管理。这样做时,我遇到了有时需要动态数据属性和值的情况。总是只有一个数据值发生变化,其他参数保持不变。这样做我可以很容易地链接承诺。

因此,这里是我用作这些 Ajax 调用模板的示例:

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. 然后我使用 eval (yes, evil) 来解析当前上下文 ( fetchChain) 的变量并将其提供给fetchData. 这些函数在命名空间内执行,所以我namespace.fetchChain(prepareAjax)在示例中调用它们。

问题

此示例仅适用于一次迭代,因为 eval 似乎也会obj永久更改,即使我只 eval/修改tempObj,但显然我想在每次迭代中重用模板。唯一需要解决的值是item,参数保持不变。

我也知道new Function()这是一个更好的选择,eval但我也无法让它工作。对我来说更奇怪的是,该函数以前在直接在 Ajax-Call 内部评估数据属性时工作,而不使用像 for 这样的准备函数fetchChain()。即使在阅读了关于 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像上面描述的那样执行时,我Unexpected Identifier在 eval 内的第二次迭代中得到了错误。([object Object]) 调试时可以看到 . 的obj值也发生了变化data

4

2 回答 2

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
于 2018-12-04T00:20:14.893 回答
0

在尝试摆脱时,eval()我遇到了与 eval 相同的问题→原始对象也总是被更改,这样所有动态参数在执行结束时都是相同的。

原来我对 '='-Operator 如何作用于对象有一个根本的误解。对象不会被克隆而是被引用。由于已经有更好的解释答案取决于 js 中的克隆对象,我只是在这里链接到一个答案。

因此,当我在 上使用时实际发生evaltempObj是,它不仅将模板字符串(数据属性)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'
    }]
}

最后但并非最不重要的一个示例,说明如何在不使用 eval 的情况下执行此操作:

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'
    }]
}
于 2018-12-04T07:20:06.867 回答