使用Promises和Fetch API javascript提取多个文件

时间:2018-10-23 03:41:24

标签: javascript ecmascript-6

我正在用Promises更新我的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
            });
        }
    });
}

3 个答案:

答案 0 :(得分:0)

有两个问题。首先,您需要返回def quickSelect(aList, k): """ Sort the list until the k'th element is found :param aList: given list :param k: the element to find (k'th) :return: The median value of the given list """ # print("qS at it again: ", aList, "with a length of: ", len(aList)) if len(aList) != 0: pivot = aList[len(aList) // 2] smallerList = [] largerList = [] count = 0 for dist in range(len(aList)): if aList[dist] > pivot: largerList.append(aList[dist]) elif aList[dist] < pivot: smallerList.append(aList[dist]) else: count += 1 m = len(smallerList) if m <= k < m + count: return pivot elif m > k: return quickSelect(smallerList, k) else: return quickSelect(largerList, k - m - count) return aList[0] 进行的Promise.all调用,以便在您的xRequire中使用它:

xRequire(..).then

此外,当您使用return Promise.all(promisesList); 时,如果最初拒绝了.catch,它将进入Promise块,执行其中的所有代码,然后是{ {1}}链将解决 (而不是拒绝)到catch块返回的内容。如果要在Promise链中渗透错误,请将catch放在链中要检测到错误的位置:

Promise

我建议您仅将catch 放到urls.forEach( (url, i) => { // (1) promisesList.push( fetch(url) .then(handleResponse) .then(data => console.log(data)) // no catch here ); }); 的呼叫方中,这样, it 会看到所有错误。您的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) ); } 链的上方,请在{{ 1}},因此它解析为的xRequire拒绝,而不是解析:

Promise

答案 1 :(得分:0)

您可以将其重写为异步等待代码吗?这是典型流程的粗略概念:

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);

答案 2 :(得分:0)

我终于以这种方式解决了它-到目前为止,我发现了唯一的古怪之处:<​​em> 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));
}