Перенос результата из обещания в массив - PullRequest
0 голосов
/ 26 июня 2018

Я пытаюсь очистить, а затем снова заполнить массив значением, возвращенным из обещания. Однако, когда я делаю это, он не всегда добавляет их обратно в том же порядке.

$scope.$watch ('timeRange', function (newValue, oldValue, scope){
     $scope.chartdata = []
     //If a filter has changed, redraw all charts
     if (newValue !== oldValue)
     {
        for(var i = 0; i< $scope.charts.length; i++){
           $scope.draw($scope.charts[i]).then(function(value){
               $scope.chartdata.push(value);
           });
        }
     }
}, true);

Это отображается с повторением ng.

Ответы [ 3 ]

0 голосов
/ 26 июня 2018

Фрагмент с ошибкой

function randInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

function asyncFunc(index) {
  return new Promise((resolve) => {
    setTimeout(() => resolve(index), randInt(0, 3000));
  });
}

const results = [];

for (var i = 0; i < 5; i++) {
  asyncFunc(i)
    .then((ret) => {
      results.push(ret);
    });
}

setTimeout(() => {
  console.log(results);
}, 4000);

Фрагмент с раствором

Мы можем передать положение данных внутри функции IEFF.

function randInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

function asyncFunc(index) {
  return new Promise((resolve) => {
    setTimeout(() => resolve(index), randInt(0, 3000));
  });
}

const results = [];

for (var i = 0; i < 5; i++) {
  (function(j) {
    asyncFunc(i)
      .then((ret) => {
        results[j] = ret;
      });
  })(i);
}

setTimeout(() => {
  console.log(results);
}, 4000);
0 голосов
/ 26 июня 2018

Простой способ сделать это - использовать .map и Promise.all (или $q.all() в AngularJS). Это сохранит порядок элементов и, как дополнительное преимущество, позволит вам определить, когда полный массив был заполнен.

Немного заимствуя пример кода из ответа Грегори:

( Примечание: Ниже приведены setTimeout, new Promise и Promise.all в целях предоставления простой иллюстративной демонстрации в виде исполняемого фрагмента стека. В реальном коде AngularJS вы не нужно setTimeout или new Promise, и вы должны использовать $q.all вместо Promise.all, как показано в примере в конце)

function randInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

function delay(ms) {
  return new Promise(function (resolve) { setTimeout(resolve, ms); });  
}

function asyncFunc(value) {
  return delay(randInt(0, 3000))
  .then(function () { 
      console.log(value, 'finished');
      return value * 2 + 1;
  });
}

const origArray = [0, 1, 2, 3, 4];

Promise.all(origArray.map(asyncFunc))
    .then(function (resultArray) {
      console.log(resultArray);
    });

Применяя это к вашему конкретному коду, мы получим:

$scope.$watch ('timeRange', function (newValue, oldValue, scope){
     $scope.chartdata = []
     //If a filter has changed, redraw all charts
     if (newValue !== oldValue)
     {
        $q.all($scope.charts.map($scope.draw))
            .then(function (resultArray) {
                $scope.charts = resultArray;
            });
     }
}, true);
0 голосов
/ 26 июня 2018

Поскольку вы делаете вещи асинхронно, порядок разрешения может быть не гарантирован. Вы можете использовать индекс i вместо push

$scope.$watch ('timeRange', function (newValue, oldValue, scope){
     $scope.chartdata = []
     //If a filter has changed, redraw all charts
     if (newValue !== oldValue)
     {
        for(var i = 0; i< $scope.charts.length; i++){
           $scope.draw($scope.charts[i]).then(function(i) { // create scope to capture i
               return function(value) { $scope.chartdata[i] = value; };
           }(i));
        }
     }
}, true);

UPD Пример добавлен только для демонстрации @georgeawg, как работает область действия

var arr = [1, 2, 3];

for (var i = 0; i < arr.length; i++) {
  setTimeout(function(i) {
    return function() {
      console.log(`Let's teach @georgeawg scopes ${i}`)
    }
  }(i), i * 1000)
}

Или используя forEach

$scope.$watch ('timeRange', function (newValue, oldValue, scope){
     $scope.chartdata = []
     //If a filter has changed, redraw all charts
     if (newValue !== oldValue)
     {
        $scope.charts.forEach(function(chart, i) {
          $scope.draw(chart).then(function(value) {
             $scope.chartdata[i] = value;
          })
        })
     }
}, true);

Или добавить все сразу, используя Promise.all или его аналог angularjs $q.all.

$scope.$watch ('timeRange', function (newValue, oldValue, scope){
     $scope.chartdata = []
     //If a filter has changed, redraw all charts
     if (newValue !== oldValue)
     {
        $q.all($scope.charts.map(function(chart) {
          return $scope.draw(chart)
        }).then(function(chartdata) {
          $scope.chartdata = chartdata;
        })
     }
}, true);
...