[英]Fetching multiple files using Promises and Fetch API javascript
I am updating my javascript skills with Promises, already have in place a library with XHR and callbacks to load and inject multiple files at once and only proceed if ALL of them succeeded.我正在使用 Promises 更新我的 javascript 技能,已经有一个带有 XHR 和回调的库,可以一次加载和注入多个文件,并且只有在所有文件都成功时才继续。
I am trying to use Promise.all() and Fetch API to get a similar functionality but can't make it work: console.log('All the promises are resolved', values);我正在尝试使用 Promise.all() 和 Fetch API 来获得类似的功能,但无法使其工作:console.log('All the promises areresolution', values); always triggers no matter if some of the fetch promises failed.
无论某些 fetch 承诺是否失败,总是会触发。
I want to be able to execute the code below, and only proceed with nowInitialize function if all the files were able to be fetched, or throw error using catch() with the reason of the first file that failed我希望能够执行下面的代码,并且只有在所有文件都能够被获取时才继续使用 nowInitialize 函数,或者由于第一个文件失败的原因使用 catch() 抛出错误
xRequire(['index.html', 'style.cds'])
.then(nowInitialize)
.catch(reason => 'One or more files failed to load' + reason)
style.cds will obviously fail 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
});
}
});
}
Can you just rewrite it as async-await code?您可以将其重写为异步等待代码吗? Here is a rough idea of the typical flow:
以下是典型流程的粗略概念:
const [data1, data2, data3] = await Promise.all([
fetch(url1),
fetch(url2),
fetch(url3),
]);
In other words, Promise.all()
returns the promise to all the data that is returned from your multiple fetch()
functions.换句话说,
Promise.all()
返回对从多个fetch()
函数返回的所有数据的承诺。
Then, if you put this into a try-catch, you can handle the rejection as well:然后,如果你把它放到 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);
}
If you want to loop with async-await
, you can do that:如果你想用
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);
There are two problems.有两个问题。 First, you need to return the
Promise.all
call from xRequire
in order to consume it in your xRequire(..).then
:首先,您需要从
xRequire
返回Promise.all
调用,以便在xRequire(..).then
使用它:
return Promise.all(promisesList);
Also, when you use .catch
, if a Promise
is initially rejected, it will go into the catch
block, do whatever code is there, and then the Promise
chain will resolve (not reject) to whatever the catch
block returns.此外,当您使用
.catch
,如果Promise
最初被拒绝,它将进入catch
块,执行那里的任何代码,然后Promise
链将解析(而不是拒绝) catch
块返回的任何内容。 If you want to percolate errors up the Promise
chain, put your catch
at the point in the chain at which you want to detect errors:如果您想将错误向上渗透
Promise
链,请将您的catch
放在链中您想要检测错误的位置:
urls.forEach( (url, i) => { // (1)
promisesList.push(
fetch(url)
.then(handleResponse)
.then(data => console.log(data))
// no catch here
);
});
I would suggest putting your catch
only in the caller of xRequire
, that way it will see all errors.我建议只将您的
catch
放在xRequire
的调用者中,这样它就会看到所有错误。 Your xRequire
function can be reduced to:您的
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)
);
}
If you want the body of xRequire
to be able to see errors, but you also want to percolate errors up the Promise
chain, throw an error in a catch
inside xRequire
, so that the Promise
it resolves to will reject , rather than resolve:如果您希望
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;
})
}
I finally solved it in this way --with the only quirk i've found so far: files argument always needs to be an array , therefore always needs brackets when calling the function--我终于以这种方式解决了它——到目前为止我发现的唯一怪癖:文件参数总是需要是一个数组,因此在调用函数时总是需要括号——
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.