Обещание в петле! Как? - PullRequest
0 голосов
/ 03 мая 2018

Я пытался заставить этот кусок кода работать некоторое время, и я просто не могу его получить. Он предназначен для динамически обновляемого графа, который принимает массив [x, y] для каждой точки, поэтому массив массивов.

Входные данные представляют собой список JSON, поступающий с сервера, который обновляет тот же самый объект JSON (поэтому он меняет один JSON и обновляет только значение):

[
  {
    "Value": 10,
    "Name": "Name of variable"
  }
]

Мне нужно только извлечь значение.

Я попробовал это так:

var getValueData = async function() {
    var valueJSON = await Promise.resolve($.getJSON( "{% url 'get_value' %}" ));
    return valueJSON[0]['Value'];
};

var data = [];
var totalPoints = 100;
var updateInterval = 1000;
var now = new Date().getTime();

function getData() {
    data.shift();

    while (data.length < totalPoints) {
        var value = [now += updateInterval,
                    getValueData().then(function(result) {
                        result;
                    })
                   ];

        data.push(value);
    };
};

По сути, getData() пытается создать массив из X = timestamp.now() и Y = "Value" из JSON, а затем вставить этот массив в мой "overall" массив данных.

Делая это таким образом, value становится массивом [<timestamp>, Unresolved].

Делаем так:

while (data.length < totalPoints) {
    getZScoreData().then(function (result) {
        var valueArray = [now += updateInterval, result];
        data.push(valueArray);
    });
};

Делает valueArray фактическим [<timestamp>, <JSON "value"], если я console.log(value), за исключением этого, кажется, что сервер зависает навсегда и потребляет огромное количество оперативной памяти для вкладки, как если бы я делал бесконечный цикл (сотни запросов на получение веб-сервера, хотя максимальная длина должна составлять 100). Я не уверен в том, что происходит внутри Обещания, чтобы добиться такого поведения.

Вот код, который работает в примере:

while (data.length < totalPoints) {     
    var y = Math.random() * 100;
    var value = [now += updateInterval, y];

    data.push(value);
};

Это кажется достаточно простым. Где написано y (в var value = [now += updateInterval, y];), заставить «y» получить значение из моего API.

Понятия не имею, как на самом деле этого добиться.

Я следую примеру из этого примера Flot , но мне просто не удается заставить его работать с фактическим живым значением из AJAX или Promise (я даже пытался получить).

Все примеры для «живого обновления таблицы» заканчиваются просто использованием math.random(), что довольно обманчиво, так как оно просто движется, но на самом деле не работает.

Полагаю, что я не решаю обещание в цикле должным образом, но из-за недостатка опыта на данный момент я даже не уверен, что не так.

Я не уверен, куда в моем коде я бы пошел Y = "live value", или я должен возвращать результат где-нибудь? Я не очень хорошо знаком с Promises или AJAX.

Ответы [ 3 ]

0 голосов
/ 03 мая 2018

Вы можете сгенерировать массив Обещаний и затем ждать разрешения с помощью Promise.all.

// Let's imitate some async operation
// It is instead of your getValueData
function twiceAsync(a) {
  // returns a promise resolving to twice argument
  return new Promise(function(ok) {
    setTimeout(function(){ok(2*a)}, 100);
  });
}

var pList = [];
for (var i = 0; i < 100; ++i) {
  // collect promises returned by twiceAsync to an array
  pList.push(twiceAsync(i));
}

Promise.all(pList) // provide array of promises to Promise.all
  .then(function(results) { // receive resolved results, they should be even numbers from 0*2 to 99*2
    console.log(results);
  })
0 голосов
/ 03 мая 2018

Некоторые вещи, которые вы должны иметь в виду

  • Ваш getValueData не достигает оператора возврата, потому что он разрешается, как только достигает Promise.resolve. (В моем примере, теперь getData возвращает обещание)
  • Используйте Promise.all, чтобы не ждать для завершения предыдущего до выполнения следующего ... разрешается, как только каждое обещание в рейде разрешается, или одно из них не удается (вы должны .catch, что).
  • Узнайте больше о Обещаниях , поначалу они страшны, но вы в конечном итоге полюбите их

Попробуйте этот код, он может не работать, потому что у меня нет полного рабочего примера, но вы можете обойти ошибки, вероятно, и заставить его работать.

var results = [],
    totalPoints = 100,
    pointsLeft = totalPoints, // since we are using Promise.all, now we have to track this instead of results.length
    updateInterval = 1000,
    promises = [],
    getValueData = async function(timestamp) {
        await $.getJSON('yourURL').done(function (data) {
           pointsLeft-- // promise fulfilled 
           Promise.resolve({ data, timestamp })
        }).fail(Promise.reject)
    };

function getData() {
    // results.shift(); why?

    while (pointsLeft) {
        // push the promise to the stack, collect them later
        promises.push(getValueData(Date.now()))
    };


    Promise.all(promises).then(function (responses) {
        responses.forEach(function (data, timestamp) {
            results.push([timestamp, data])
        })
    }).catch(console.warn)
};
0 голосов
/ 03 мая 2018

Обещания в циклах редко бывают хорошей идеей, обычно вам нужно использовать Promise.all() для одновременного выполнения нескольких Обещаний и получения их результатов в массиве:

function getData() {
    // Note: Why is this here?
    data.shift();

    var promises = [];
    while (data.length < totalPoints) {
        promises.push(getValueData());
    }

    Promise.all(promises).then(results => {
        for (let result of results) {
            var value = [
                now += updateInterval,
                result
            ];
            data.push(value);
        }
    });
};

У MDN есть хорошие материалы по Обещаниям: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises

Как примечание: выполнение 100 запросов AJAX одновременно звучит довольно напряженно, даже с Promise.all(). Вам следует либо попытаться оптимизировать бэкэнд, если у вас есть какое-либо влияние на него, либо заглянуть в Worker s для выполнения запросов в пакетном режиме.

...