Действительно запустить выборку несколько раз синхронно - PullRequest
0 голосов
/ 17 мая 2018

Я видел различные решения, позволяющие сделать выборку синхронной, например использование await, но затем они должны быть обернуты в асинхронную функцию, поэтому все это не будет синхронным.

Мне нужно запустить fetch x раз и завершить каждую итерацию в том порядке, в котором она была начата. Если я использую .then после выборки, она запускается после каждого экземпляра выборки, но результаты, включая результаты функции, выполняемой .then, возвращаются в порядке ответа, поэтому список URL-адресов извлекается в порядке z, на выходе может возвращаться частично случайный порядок, что недопустимо.

Я пытался использовать jquery ajax с async: false, и хотя он сохраняет вывод в порядке с вводом - при успешном выполнении - он зависает на неопределенное время при ошибке, и его значение тайм-аута не работает синхронно режим.

По-видимому, у нас есть выбор извлечения нескольких последовательных URL-адресов в потенциально случайном порядке, или мы можем получить их в порядке , с помощью jquery ajax / XMLHTTPRequest в синхронном режиме, но затем заморозить браузер, когда URL-адрес out, в то время как значение тайм-аута, которое мы установили для прекращения попытки получить URL, игнорируется.

Вот пример, который читает текстовый файл адресов, по одному на строку, выбирает район их городского совета и добавляет его к этой строке. Это работает - за исключением того, что выходные строки не в том же порядке, что и входные, и я не нашел способа получить их, без остановки на неопределенное время по истечении времени ожидания URL, в синхронном режиме.

<!DOCTYPE html>
<html><head><body>
  <h1>LAS - Find My District Widget</h1>
  <h2>Select a text file (.txt) with a list of addresses - each in a new line.  The Widget will return the corresponding districts.</h2>
  <input id="input-file" type="file">
  <hr><textarea id="output-box" cols="250"></textarea>
<script>
var baseUrl = "https://changedthistoprotectprivacy";
var input = document.getElementById('input-file');
var output = document.getElementById('output-box');

function writeSuccesOutput(geoclientResp) {
  var address = geoclientResp.input.replace(/(?:\r\n|\r|\n)/g,"");
  var cityCouncil = geoclientResp['results'][0].response.cityCouncilDistrict;
  var addressWithCcd = address + ' City Council District ' + cityCouncil + '\n';
  output.textContent += addressWithCcd;
}

function writeErrorOutput(error) {
  var address = geoclientResp.input.replace(/(?:\r\n|\r|\n)/g,"");
  var message = address + ' ERROR ' + error + '\n';
  output.textContent += message;
}

function geocode(address) {
  var querystring = encodeURI(address);
  var url = baseUrl + querystring;
  fetch(url).then(function(response) {
    response.json().then(writeSuccesOutput);
  }).catch(writeErrorOutput);
}

var reader = new FileReader();
reader.onloadend = function (event) {
  output.textContent = ''
  var addressList = event.target.result.split("\n");
  for (var i = 0; i < addressList.length; i++) {
    geocode(addressList[i]);
  }
}

input.onchange = function() {
  if (this.files && this.files[0]) {
    reader.readAsBinaryString(this.files[0]);
  }
}
</script>
</body>
</html>

1 Ответ

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

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

Promise.all ()

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

var reader = new FileReader();
reader.onloadend = function (event) {
  output.textContent = ''
  var addressList = event.target.result.split("\n");
  var prmises = addressList.map(address => geocode(address));
  Promise.all(promises).then(coordinates => {
    // here coordinates[0] is result for addressList[0] and so on
    
  });
}

// Here is a demo
const fakeApi = (address) => {
   const randrom = Math.random() * 1000 + 1000;
     return new Promise(resolve => {
     setTimeout(() => resolve(`${address}_${randrom}`), 10);
   });
};

const addresses = ['A', 'B', 'C', 'D', 'E', 'F'];

const promises = addresses.map(address => fakeApi(address));
console.log(addresses);
Promise.all(promises).then(results => {
  console.log(results);
});
...