我有以下函数,由另一个函数调用:
function fetchAllRecords(client, item, region, offset, savedCount, totalCount) {
offset = offset || 1;
savedCount = savedCount || 0;
totalCount = totalCount || 0;
return processQueue(client, item, offset, region).then(function (result) {
return associate(result, item, region)
}).then(function (success) {
return saveBatch(item, success.allResources, region);
}).then(function (result) {
savedCount += result.savedCount;
totalCount += result.totalCount;
if (debugmode) {
console.log(savedCount + '/' + totalCount);
}
offset += item.limit;
return fetchAllRecords(client, item, region, offset, savedCount, totalCount);
}).catch(function (err) {
if (err == 'done')
return 'done';
// All of the above steps have built-in retry so we assume there's a non-recoverable error in this batch and move to next
if (err.message === 'LIMIT_EXCEEDED') {
offset += item.limit;
return fetchAllRecords(client, item, region, offset, savedCount, totalCount);
}
else {
******************* Problem Line ********************
console.log('Miscellenious error in fetachAllRecords, moving to next resource');
console.log(JSON.stringify(err));
throw new Error('Misc');
}
});
}
在其他函数
中被调用function processResource(client, item, debugmode, region) {
var deferred = q.defer();
if (item.resource === "Property" && region === "ccmls") {
var cities = cities.list;
item.query = item.query + ' ,(City=|' + cities.join() + ')';
}
fetchAllRecords(client, item, region)
.then(function (result) {
if (debugmode) {
console.log('fetchAllRecords: ' + item.resource + '.' + item.class + ' completed...');
}
deferred.resolve(result);
})
.catch(function (err) {
console.log(item.resource + '.' + item.class + ' failed with error: ' + JSON.stringify(err));
deferred.reject(err);
});
return deferred.promise;
}
在上面的问题行中,它应该拒绝fetchAllRecords
,而在processResource
中应该调用fetachAllResources
catch
处理程序,但出于某种奇怪的原因,这个问题在被抛出后被调用十几次(随机)它最终拒绝了fetchAllResources
中processResource
返回的承诺。
我错过了一些明显的东西吗?还请评论我使用承诺的风格,是不是还是需要更多练习?
答案 0 :(得分:1)
我认为您收到的错误可能发生在您对堆栈中的方法进行十几次调用之后。
即,假设您在调用processQueue方法时遇到以下情况:
成功,成功,成功,其他失败
现在,观察我在下面的代码中标记的行。 (我将引用这些行,例如LINE A2,它将在fetchAllRecords的第二次调用中引用LINE A):
function fetchAllRecords(client, item, region, offset, savedCount, totalCount) {
offset = offset || 1;
savedCount = savedCount || 0;
totalCount = totalCount || 0;
/*********************** LINE A **************************/
return processQueue(client, item, offset, region).then(function (result) {
return associate(result, item, region)
}).then(function (success) {
return saveBatch(item, success.allResources, region);
}).then(function (result) {
savedCount += result.savedCount;
totalCount += result.totalCount;
if (debugmode) {
console.log(savedCount + '/' + totalCount);
}
offset += item.limit;
/*********************** LINE B **************************/
return fetchAllRecords(client, item, region, offset, savedCount, totalCount);
}).catch(function (err) {
if (err == 'done')
return 'done';
// All of the above steps have built-in retry so we assume there's a non-recoverable error in this batch and move to next
if (err.message === 'LIMIT_EXCEEDED') {
offset += item.limit;
return fetchAllRecords(client, item, region, offset, savedCount, totalCount);
}
else {
/*********************** LINE C **************************/
console.log('Miscellenious error in fetachAllRecords, moving to next resource');
console.log(JSON.stringify(err));
/*********************** LINE D **************************/
throw new Error('Misc');
}
});
}
我们输入的内容是:
这导致行D被调用的次数比流程资源中的catch块多出许多次。
希望这是有道理的。
你对promises的使用 - 你在processResource方法中使用了反模式(参考:https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns#the-deferred-anti-pattern) - 你应该很少自己创建deferred,相反,你可以依赖于当时的链接行为并捕获(见https://github.com/kriskowal/q)。也就是说,你可以这样写:
function processResource(client, item, debugmode, region) {
if (item.resource === "Property" && region === "ccmls") {
var cities = cities.list;
item.query = item.query + ' ,(City=|' + cities.join() + ')';
}
return fetchAllRecords(client, item, region)
.then(function (result) {
if (debugmode) {
console.log('fetchAllRecords: ' + item.resource + '.' + item.class + ' completed...');
}
return result;
})
.catch(function (err) {
console.log(item.resource + '.' + item.class + ' failed with error: ' + JSON.stringify(err));
return Q.reject(err);
});
}
更一般地说,如果你有能力转换器,我建议使用像babel(或打字稿)这样的东西 - 这意味着你可以使用ES6箭头函数表示法编写,这可以使promises更具可读性
答案 1 :(得分:1)
您正在获取大量日志,因为您使用递归方法,并在每个级别处理和重新抛出错误。同步写入,它与
完全相同function fetchAll(offset) {
if (offset > 5) throw new Error("message"); // let's say the inner one throws
try {
return fetchAll(offset+1);
} catch(e) {
console.error(e.message);
throw e;
}
}
fetchAll(0);
你也希望在这里收到5条消息,对吧?
解决方案不是再次处理内部结果的错误。要实现承诺,请查看difference between .then(…).catch(…)
and .then(…, …)
- 您需要后者:
function fetchAllRecords(client, item, region, offset=1, savedCount=0, totalCount=0) {
return processQueue(client, item, offset, region).then(function (result) {
return associate(result, item, region)
}).then(function (success) {
return saveBatch(item, success.allResources, region);
}).then(function (result) {
savedCount += result.savedCount;
totalCount += result.totalCount;
if (debugmode) {
console.log(savedCount + '/' + totalCount);
}
offset += item.limit;
return fetchAllRecords(client, item, region, offset, savedCount, totalCount);
}, function (err) {
// ^^
if (err == 'done')
return 'done';
if (err.message === 'LIMIT_EXCEEDED') {
offset += item.limit;
return fetchAllRecords(client, item, region, offset, savedCount, totalCount);
} else {
console.log('Miscellenious error in fetchAllRecords, moving to next resource');
console.log(JSON.stringify(err));
throw new Error('Misc');
}
});
}
function processResource(client, item, debugmode, region) {
if (item.resource === "Property" && region === "ccmls") {
var cities = cities.list;
item.query = item.query + ' ,(City=|' + cities.join() + ')';
}
return fetchAllRecords(client, item, region)
.then(function (result) {
if (debugmode) {
console.log('fetchAllRecords: ' + item.resource + '.' + item.class + ' completed...');
}
return result;
}, function (err) {
console.log(item.resource + '.' + item.class + ' failed with error: ' + JSON.stringify(err));
throw err;
});
}