[英]Fetching multiple files using Promises and Fetch API javascript
我正在使用 Promises 更新我的 javascript 技能,已经有一个带有 XHR 和回调的库,可以一次加载和注入多个文件,并且只有在所有文件都成功时才继续。
我正在尝试使用 Promise.all() 和 Fetch API 来获得类似的功能,但无法使其工作:console.log('All the promises areresolution', values); 无论某些 fetch 承诺是否失败,总是会触发。
我希望能够执行下面的代码,并且只有在所有文件都能够被获取时才继续使用 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
});
}
});
}
您可以将其重写为异步等待代码吗? 以下是典型流程的粗略概念:
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);
有两个问题。 首先,您需要从xRequire
返回Promise.all
调用,以便在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
的调用者中,这样它就会看到所有错误。 您的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;
})
}
我终于以这种方式解决了它——到目前为止我发现的唯一怪癖:文件参数总是需要是一个数组,因此在调用函数时总是需要括号——
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));
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.