Извлечение нескольких файлов с помощью JavaScript и Promet API Fetch - PullRequest
0 голосов
/ 23 октября 2018

Я обновляю свои навыки работы с javascript с помощью Promises, у меня уже есть библиотека с XHR и обратными вызовами для загрузки и внедрения нескольких файлов одновременно, и я продолжаю работу, только если ВСЕ из них успешно выполнены.

Я пытаюсь использоватьPromise.all () и Fetch API для получения аналогичной функциональности, но не могут заставить ее работать: console.log («Все обещания разрешены», значения);всегда срабатывает независимо от того, были ли сбиты некоторые обещания выборки.

Я хочу иметь возможность выполнить приведенный ниже код и продолжать работу с функцией nowInitialize только в том случае, если все файлы были получены, или выдает ошибку, используя catch() с причиной первого файла, который потерпел неудачу

xRequire(['index.html', 'style.cds'])
  .then(nowInitialize)
  .catch(reason => 'One or more files failed to load' + reason)

style.cds, очевидно, потерпит неудачу

//TODO Handle file types appropriately
//TODO: Inject css, javascript files

function xRequire(files) {
    let urls = [];
    let promisesList = [];
    let handleAllPromises;


//Populates urls with each file required
for(let i=0; i < files.length ; i++) {
    urls.push(files[i]);
}
//Fetch each file in urls
urls.forEach( (url, i) => { // (1)
    promisesList.push(
        fetch(url)
            .then(handleResponse)
            .then(data => console.log(data))
            .catch(error => console.log(error))
    );
});

handleAllPromises = Promise.all(promisesList);
handleAllPromises.then(function(values) {
    console.log('All the promises are resolved', values);
});
handleAllPromises.catch(function(reason) {
    console.log('One of the promises failed with the following reason', reason);
});
}

function handleResponse(response) {
let contentType = response.headers.get('content-type');
console.log('Requested Info: ' + contentType);
if (contentType.includes('application/json')) {
    return handleJSONResponse(response);
} else if (contentType.includes('text/html')) {
    return handleTextResponse(response);
} else if (contentType.includes('text/css')) {
    return handleTextResponse(response);
} else if (contentType.includes('application/javascript')) {
    return handleTextResponse(response);
} else {
    throw new Error(`Sorry, content-type ${contentType} not supported`);
}
}

function handleJSONResponse(response) {
return response.json()
    .then(json => {
        if (response.ok) {
            return json;
        } else {
            return Promise.reject(Object.assign({}, json, {
                status: response.status,
                statusText: response.statusText
            }));
        }
    });
}

function handleTextResponse(response) {
return response.text()
    .then(text => {
        if (response.ok) {
            return text;
        } else {
            return Promise.reject({
                status: response.status,
                statusText: response.statusText,
                err: text
            });
        }
    });
}

Ответы [ 3 ]

0 голосов
/ 23 октября 2018

Можете ли вы просто переписать его как асинхронный код?Вот примерное представление о типичном потоке:

const [data1, data2, data3] = await Promise.all([
  fetch(url1),
  fetch(url2),
  fetch(url3),
]);

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

Затем, если вы поместите это в try-catch, вы также можете обработать отклонение:

try {
  const [data1, data2, data3] = await Promise.all([
    fetch(url1),
    fetch(url2),
    fetch(url3),
  ]);

  // Now you can process the data:
  [data1, data2, data3].map(handleResponse);
} catch (error) {
  console.log('Error downloading one or more files:', error);
}

Если вы хотите выполнить цикл с async-await, вы можете сделать это:

const promises = [];
for (const url of [url1, url2, url3, url4]) {
  promises.push(fetch(url));
}

const [data1, data2, data3, data4] = await Promise.all(promises);
0 голосов
/ 27 октября 2018

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

xRequire(['my-file'])
   .then(handle success)
   .catch(handle error);

async function xRequire(files) {
    let promises = [];
    let receivedData;

    //Iterate over files array and push results of fetch to promises array
    files.map(x => promises.push(fetch(x)));
    //populate receivedData array from promises array
    receivedData = await Promise.all(promises);
    //iterate over receivedData to handle each response accordingly
    return receivedData.map(x => handleResponse(x));
}
0 голосов
/ 23 октября 2018

Есть две проблемы.Во-первых, вам нужно вернуть Promise.all вызов от xRequire, чтобы использовать его в вашем xRequire(..).then:

return Promise.all(promisesList);

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

urls.forEach( (url, i) => { // (1)
  promisesList.push(
    fetch(url)
    .then(handleResponse)
    .then(data => console.log(data))
    // no catch here
  );
});

Я бы предложил поставить вашу catch только в вызывающем из xRequire, таким образом it будет видеть все ошибки.Ваша функция xRequire может быть уменьшена до:

xRequire(['index.html', 'style.cds'])
  .then(nowInitialize)
  .catch(reason => 'One or more files failed to load' + reason)

function xRequire(files) {
  return Promise.all(
    urls.map(handleResponse)
  );
}

Если вы хотите, чтобы тело xRequire могло видеть ошибки, но вы также хотите получать ошибки вверх по цепочке Promise, бросьтеошибка в catch внутри xRequire, поэтому Promise, которое он разрешает, будет отклонять , а не разрешать:

function xRequire(files) {
  return Promise.all(
    urls.map(handleResponse)
  )
  .catch((err) => {
    console.log('There was an error: ' + err);
    throw err;
  })
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...