Подготовьте переменные контекста B в контексте A и разрешите их в контексте B - PullRequest
0 голосов
/ 04 декабря 2018

В настоящее время я пытаюсь сделать динамические повторяющиеся вызовы 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);

            }
        );
    }
}

То, что я здесь делаю, - это создание обещания и Ajax-Call для каждого ìterateValue.Затем я использую eval (да, зло), чтобы разрешить переменные текущего контекста (fetchChain) и передать его в fetchData.Функции выполняются в пространстве имен, поэтому я вызываю их, например, с namespace.fetchChain(prepareAjax).

Проблема

Этот пример работает только для одной итерации, начиная с evalтакже, кажется, постоянно меняет obj, даже если я только оцениваю / модифицирую tempObj, но, очевидно, я хочу повторно использовать шаблон на каждой итерации.Единственное значение, которое необходимо разрешить, - это item, параметры остаются прежними.

Я также знаю, что new Function() - лучшая альтернатива eval, но я не смог заставить его работать.Что для меня более странно, так это то, что функция работала ранее, когда оценивала атрибуты данных непосредственно внутри Ajax-Call, без использования функции подготовки, такой как 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.([объект Объект]) При отладке можно было увидеть, что obj также изменил свое значение на data.

Ответы [ 2 ]

0 голосов
/ 04 декабря 2018

При попытке избавиться от eval() я столкнулся с теми же проблемами, что и с eval → Исходный объект тоже всегда менялся, и таким образом все динамические параметры были одинаковыми к концу выполнения.

ПоворотыУ меня возникло фундаментальное недоразумение о том, как '=' - оператор работает с объектами.Объекты не клонируются, а ссылаются на них.Поскольку в js уже есть объясненные ответы, лучше связанные с клонированием объектов, я просто ссылаюсь на один ответ здесь .

Так что же на самом деле происходит при использовании 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'
    }]
}

Последний, но не менее важный пример, как это сделать без 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'
    }]
}
0 голосов
/ 04 декабря 2018

Почему бы вам не сделать что-то подобное для динамического получения этого объекта?

например:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...