使用Promises和FetchAPI javascript获取多个文件

使用Promises和FetchAPI javascript获取多个文件,javascript,ecmascript-6,Javascript,Ecmascript 6,我正在用承诺更新我的javascript技能,已经有了一个包含XHR和回调的库,可以一次加载和注入多个文件,并且只有在所有文件都成功的情况下才能继续 我试图使用Promise.all()和Fetch API来获得类似的功能,但无法使其正常工作:console.log('所有承诺都已解决',值);始终触发,无论某些获取承诺是否失败 我希望能够执行下面的代码,并且只有在能够获取所有文件的情况下才能继续使用nowInitialize函数,或者使用catch()抛出错误,并说明第一个文件失败的原因 xR

我正在用承诺更新我的javascript技能,已经有了一个包含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
            });
        }
    });
}
//正确处理文件类型的TODO
//TODO:注入css、javascript文件
函数xRequire(文件){
让URL=[];
让允诺者列出=[];
让我们来兑现承诺;
//用所需的每个文件填充URL
for(设i=0;i{//(1)
承诺推送(
获取(url)
.然后(HandlerResponse)
.then(数据=>console.log(数据))
.catch(错误=>console.log(错误))
);
});
handleAllPromises=Promise.all(promisesList);
handleAllPromises.then(函数(值){
log('所有承诺都已解决',值);
});
handleAllPromises.catch(函数(原因){
console.log('其中一个承诺失败,原因如下');
});
}
功能句柄响应(响应){
让contentType=response.headers.get('content-type');
log('请求的信息:'+contentType);
if(contentType.includes('application/json')){
返回handleJSONResponse(response);
}else if(contentType.includes('text/html')){
返回handleTextResponse(响应);
}else if(contentType.includes('text/css')){
返回handleTextResponse(响应);
}else if(contentType.includes('application/javascript')){
返回handleTextResponse(响应);
}否则{
抛出新错误(`Sorry,内容类型${contentType}不受支持`);
}
}
函数handleJSONResponse(response){
返回response.json()
。然后(json=>{
if(response.ok){
返回json;
}否则{
返回Promise.reject(Object.assign({},json{
状态:response.status,
statusText:response.statusText
}));
}
});
}
函数handleTextResponse(响应){
返回response.text()
。然后(文本=>{
if(response.ok){
返回文本;
}否则{
回绝({
状态:response.status,
statusText:response.statusText,
错误:文本
});
}
});
}

有两个问题。首先,您需要返回
承诺。来自
xRequire
的所有
调用,以便在
xRequire(..)中使用它。然后

return Promise.all(promisesList);
另外,当您使用
.catch
时,如果
承诺最初被拒绝,它将进入
catch
块,执行那里的任何代码,然后
承诺链将解析(而不是拒绝)到
catch
块返回的任何代码。如果要在
Promise
链中过滤错误,请将
catch
放在链中要检测错误的点上:

urls.forEach( (url, i) => { // (1)
  promisesList.push(
    fetch(url)
    .then(handleResponse)
    .then(data => console.log(data))
    // no catch here
  );
});
我建议将您的
catch
仅放在
xRequire
的调用者中,这样它将看到所有错误。您的
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
链中过滤错误,请在
xRequire
内部的
catch
中抛出错误,以便它解析为的
Promise
将拒绝,而不是解析:

function xRequire(files) {
  return Promise.all(
    urls.map(handleResponse)
  )
  .catch((err) => {
    console.log('There was an error: ' + err);
    throw err;
  })
}

你能把它重写成异步等待代码吗?以下是典型流程的大致情况:

const [data1, data2, data3] = await Promise.all([
  fetch(url1),
  fetch(url2),
  fetch(url3),
]);
换句话说,
Promise.all()
将Promise返回给从多个
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 wait
循环,可以执行以下操作:

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

const [data1, data2, data3, data4] = await Promise.all(promises);

我最终以这种方式解决了这个问题——到目前为止我发现的唯一一个怪癖是:files参数总是需要是一个数组,因此调用函数时总是需要括号--


@当然你不是认真的,这不是重复的,对吧?我的意思是一个简单的搜索显示多个配音的配音,所以。。。来吧这里有一个:@Akrion我没有这么说,我只是说
async/await
语法问题不是问题所要问的(问题中至少有几个问题)。这看起来很好,但在循环处理所有被请求的文件时,我无法使用语法,例如xRequire(['url1'、'url2'、'url3'、'url4']),您能详细说明一下吗?@aalvarado在您的简化函数中添加了,您能告诉我您从服务器上实际从哪里获取文件吗?
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));
}