使用promise在for循环中请求与订单相关的信息

Using promises to request order-dependent information in a for loop

本文关键字:单相关 信息 请求 promise for 循环 使用      更新时间:2023-09-26

我有一个相对简单的任务;现有的信息已经过期,所以我必须从API请求信息,修改现有的信息文件并将其推回到服务器,更新。该信息采用json文件的形式;很简单。该文件包含一个对象,该对象具有一组必须更新的属性的对象。这就是问题发生的地方;对象数组生成一个API请求数组,其响应必须与生成请求的原始对象匹配(因为响应包含必须在对象中更新的信息)。

这就是我迄今为止所做的承诺的要点:

function main() {
    // First get existing data.
	getExistingData().then(function(result) {
	  console.log(result); // It worked, return it for next 'then' to use.
	  return result;
	}, function(err) {
	  console.log(err); // This usually never happens.
	}).then(function(result) { // Use the existing data to generate the requests for new data.
		requestNewData(result).then(function(moddedJson) {
			console.log(moddedJson); // This happens BEFORE I get responses back from the request, which is wrong.
		});
	});
}
function getExistingData() {
	return new Promise(function(resolve, reject) {
		fetch('dataURLHere')
		.then(function(res) {
	        resolve( res.json()); // Turn result into JSON, and return it.
	    })
	})
}
function requestNewData(rawJson) {
	return new Promise(function(resolve) {
        // Loop over the number of objects in the original data.
		for (var i = 0; i < rawJson.length; i++) { 
            // Loop over the array of objects within each object.
	    	for (var multiId = 0; multiId < rawJson.hits.length; multiId++) {
	    		var requestUrl = "someURLConstructedFromJsonData";
                var hit = rawJson.hits[multiId];
				new Promise(function(resolve) {
					request(requestUrl, function(error, response, body) {
					  	if (!error && response.statusCode == 200) {
                            // Need to parse the XML response into a js object.
					  		parseString(body, function (err, result) {
                                hit.propertyToChange = result.propertyToChange;
                                hit.propertyToChange2 = result.propertyToChange2;
							});
					  	}
					  	else {
					  		console.log("No data for this item.");
					  	}
						resolve(hit);
					});
				})
			}
		}
		resolve(rawJson);
	})
}

基本上,我想发生的事情是:1) 获取原始数据。这很容易,并且已经通过我的代码完成了。2) 使用原始数据为数据中的每个文档以及每个文档中的每组属性生成请求。这也不是问题。3) 确保从请求返回的数据与现有数据匹配。这是我无法理解的问题部分。

问题是解决得太早。

危险信号是当你创造了一个承诺,但从不做任何事情:

new Promise(function(resolve) {
    request(requestUrl, function(error, response, body) {
    ...

这个承诺确实得到了正确的解决,但没有人在等待它。简单的解决方案是promise.all:

function requestNewData(rawJson) {
    return new Promise(function(resolve, reject) {
        var promises = [];
        for (var i = 0; i < rawJson.length; i++) {
            ...
            promises.push(new Promise(function(resolve) {
                ...
            }));
        }
        resolve(Promise.all(promises));
    });
}

现在,Promise.all(promises)将通过一组结果进行解析。这可能并不理想,但如果你只想等待使用它,你可以,但前提是:

return Promise.all(promises).then(function() {
    resolve(updatedJson);
}, reject);

通过这种方式,您可以让每个单独的承诺修改响应数据。requestNewData返回的promise在完成所有这些操作之前不会解析,因此此时updatedJson将被更新。

请注意:Promise.all具有快速失败行为。就你而言,我认为这正是你想要的。但是,如果你需要知道哪些失败了,或者如果你需要等到所有请求完成(失败或其他),Promise.all可能不是正确的选择。

PS:如果request()函数提供了error,那么您可能应该使用reject。否则,如果出现网络错误,你的数据可能会出现漏洞,而不会被拒绝。