仅使用 Node.js Promise 的异步 HTTP(S) 遍历
Async HTTP(S) Traversal only using Node.js Promisses
我尝试遍历一堆 HAL/JSON 资源,这些资源模拟了通过 href 连接并通过 https 检索的项目树。 IE。一个 'item' 可能是一个树叶或另一个有其他树叶的分支。
las,我做对了。遍历将始终结束,即在完整递归完成之前,在我的代码示例的最后一条语句中点击 then() 回调。实际上,我只得到第一层儿童。
我的问题:我错过了什么才能做到正确?
我还在学习 Nodejs,但我已经在前面的示例中成功使用了 promises。我在这里问这个问题,因为我不得不只使用模块 https 和集成的 Nodejs 东西。其他示例经常使用其他模块
and/or没有解决我的问题
var traverse = function(rootItemUrl, depth, children) {
var deferred = Promise.defer();
var itemUrl = rootItemUrl;
var options = {
'path' : itemUrl
, 'host' : "<host>"
, 'method' : 'GET'
, 'headers' : {
'Content-Type' : 'application/json'
, 'Accept' : 'application/json'
, 'Forwarded' : 'proto=https;host=<host>'
, 'Cookie' : options_.headers['Cookie']
}
};
https.get(options, onItemResultResponse);
function onItemResultResponse(itemResultResponse) {
var body = [];
itemResultResponse.on('data', function onDataChunk(data) {
body.push(data);
});
itemResultResponse.on('end', onItemResultData);
itemResultResponse.on('error', onRequestItemsError);
function onRequestItemsError(e) {
console.log('Get items failed for <'+rootItemUrl+'>.');
deferred.reject();
}
function onItemResultData() {
var items = [];
var itemResult = JSON.parse(Buffer.concat(body).toString());
var embedded = itemResult._embedded;
var collection = embedded ? embedded['collection'] : undefined;
if(collection) {
var itemsObject = collection._links['item'];
if(itemsObject) {
if(itemsObject.length) {
for(var i = 0; i < itemsObject.length; ++i) {
items.push(itemsObject[i].href);
}
} else {
items.push(itemsObject.href);
}
}
}
var type = itemResult.base.type;
var name = itemResult.common.name;
var text = repeatChar(depth, '\t') + ('folder' === type ? '- (folder) ' : '')+ 'depth: '+depth+' '+name;
children.push(text);
//console.log(text);
if(items.length) {
for (var j = 0; j < items.length; ++j) {
traverse(items[j], depth + 1, children)
.then(function() {deferred.resolve(depth);});
}
} else {
deferred.resolve(depth);
}
}
}
return deferred.promise;
};
var children = [];
traverse(rootItemUrl, 0, children)
.then(function toConsole(depth) {
// >> Alas I hit this point too early <<
console.log(children);
console.log('End');
});
任何对这个问题的答案感兴趣的人,请继续阅读,因为我找到了一个解决方案没有承诺。我完全摆脱了支持回调的承诺。请注意,与原始代码相比,我做了一些更改,例如收集结果而不是在递归代码中将它们打印到标准输出,我删除了一些其他的绒毛。
var traverse = function(options, rootItemUrl, depth, done) {
var results = [];
options.path = rootItemUrl;
https.get(options, onItemResultResponse);
function onItemResultResponse(itemResultResponse) {
var body = [];
itemResultResponse.on('data', function onDataChunk(data) {
body.push(data);
});
itemResultResponse.on('end', onItemResultData);
itemResultResponse.on('error', onRequestItemsError);
function onRequestItemsError(e) {
console.log('Get items failed for <' + rootItemUrl + '>.');
done(e);
}
function onItemResultData() {
var items = [];
var itemResult = JSON.parse(Buffer.concat(body).toString());
var embedded = itemResult._embedded;
results.push(toItemInfo(itemResult, depth));
var collection = embedded ? embedded['collection'] : undefined;
var embeddedItems = collection ? collection._embedded : undefined;
if (embeddedItems) {
var itemsObject = embeddedItems['item'];
if (itemsObject) {
if (itemsObject.length) {
for (var i = 0; i < itemsObject.length; ++i) {
items.push(itemsObject[i]);
}
} else {
items.push(itemsObject);
}
}
var itemInfos = new Array(items.length);
for (var iii = 0; iii < items.length; ++iii) {
itemInfos[iii] = toItemInfo(items[iii], depth + 1);
}
var ii = 0;
(function next() {
var nextItemInfo = itemInfos[ii++];
if (!nextItemInfo) {
return done(null, results);
}
if ('folder' === nextItemInfo.type) {
traverse(options, nextItemInfo, depth + 1, function done(err, result) {
results = results.concat(result);
next();
});
} else {
results.push(nextItemInfo);
next();
}
})();
}
}
}
};
traverse(options, rootItemUrl, 0, function done(e, results) {
var text = '';
for(var ii = 0; ii < results.length; ++ii) {
var itemInfo = results[ii];
text += repeatChar(itemInfo.depth, '\t') + ('folder' === itemInfo.type ? '- (folder) ' : '') + 'depth: ' + itemInfo.depth + ' ' + itemInfo.name;
}
console.log(text);
console.log("End");
});
我尝试遍历一堆 HAL/JSON 资源,这些资源模拟了通过 href 连接并通过 https 检索的项目树。 IE。一个 'item' 可能是一个树叶或另一个有其他树叶的分支。 las,我做对了。遍历将始终结束,即在完整递归完成之前,在我的代码示例的最后一条语句中点击 then() 回调。实际上,我只得到第一层儿童。
我的问题:我错过了什么才能做到正确?
我还在学习 Nodejs,但我已经在前面的示例中成功使用了 promises。我在这里问这个问题,因为我不得不只使用模块 https 和集成的 Nodejs 东西。其他示例经常使用其他模块 and/or没有解决我的问题
var traverse = function(rootItemUrl, depth, children) {
var deferred = Promise.defer();
var itemUrl = rootItemUrl;
var options = {
'path' : itemUrl
, 'host' : "<host>"
, 'method' : 'GET'
, 'headers' : {
'Content-Type' : 'application/json'
, 'Accept' : 'application/json'
, 'Forwarded' : 'proto=https;host=<host>'
, 'Cookie' : options_.headers['Cookie']
}
};
https.get(options, onItemResultResponse);
function onItemResultResponse(itemResultResponse) {
var body = [];
itemResultResponse.on('data', function onDataChunk(data) {
body.push(data);
});
itemResultResponse.on('end', onItemResultData);
itemResultResponse.on('error', onRequestItemsError);
function onRequestItemsError(e) {
console.log('Get items failed for <'+rootItemUrl+'>.');
deferred.reject();
}
function onItemResultData() {
var items = [];
var itemResult = JSON.parse(Buffer.concat(body).toString());
var embedded = itemResult._embedded;
var collection = embedded ? embedded['collection'] : undefined;
if(collection) {
var itemsObject = collection._links['item'];
if(itemsObject) {
if(itemsObject.length) {
for(var i = 0; i < itemsObject.length; ++i) {
items.push(itemsObject[i].href);
}
} else {
items.push(itemsObject.href);
}
}
}
var type = itemResult.base.type;
var name = itemResult.common.name;
var text = repeatChar(depth, '\t') + ('folder' === type ? '- (folder) ' : '')+ 'depth: '+depth+' '+name;
children.push(text);
//console.log(text);
if(items.length) {
for (var j = 0; j < items.length; ++j) {
traverse(items[j], depth + 1, children)
.then(function() {deferred.resolve(depth);});
}
} else {
deferred.resolve(depth);
}
}
}
return deferred.promise;
};
var children = [];
traverse(rootItemUrl, 0, children)
.then(function toConsole(depth) {
// >> Alas I hit this point too early <<
console.log(children);
console.log('End');
});
任何对这个问题的答案感兴趣的人,请继续阅读,因为我找到了一个解决方案没有承诺。我完全摆脱了支持回调的承诺。请注意,与原始代码相比,我做了一些更改,例如收集结果而不是在递归代码中将它们打印到标准输出,我删除了一些其他的绒毛。
var traverse = function(options, rootItemUrl, depth, done) {
var results = [];
options.path = rootItemUrl;
https.get(options, onItemResultResponse);
function onItemResultResponse(itemResultResponse) {
var body = [];
itemResultResponse.on('data', function onDataChunk(data) {
body.push(data);
});
itemResultResponse.on('end', onItemResultData);
itemResultResponse.on('error', onRequestItemsError);
function onRequestItemsError(e) {
console.log('Get items failed for <' + rootItemUrl + '>.');
done(e);
}
function onItemResultData() {
var items = [];
var itemResult = JSON.parse(Buffer.concat(body).toString());
var embedded = itemResult._embedded;
results.push(toItemInfo(itemResult, depth));
var collection = embedded ? embedded['collection'] : undefined;
var embeddedItems = collection ? collection._embedded : undefined;
if (embeddedItems) {
var itemsObject = embeddedItems['item'];
if (itemsObject) {
if (itemsObject.length) {
for (var i = 0; i < itemsObject.length; ++i) {
items.push(itemsObject[i]);
}
} else {
items.push(itemsObject);
}
}
var itemInfos = new Array(items.length);
for (var iii = 0; iii < items.length; ++iii) {
itemInfos[iii] = toItemInfo(items[iii], depth + 1);
}
var ii = 0;
(function next() {
var nextItemInfo = itemInfos[ii++];
if (!nextItemInfo) {
return done(null, results);
}
if ('folder' === nextItemInfo.type) {
traverse(options, nextItemInfo, depth + 1, function done(err, result) {
results = results.concat(result);
next();
});
} else {
results.push(nextItemInfo);
next();
}
})();
}
}
}
};
traverse(options, rootItemUrl, 0, function done(e, results) {
var text = '';
for(var ii = 0; ii < results.length; ++ii) {
var itemInfo = results[ii];
text += repeatChar(itemInfo.depth, '\t') + ('folder' === itemInfo.type ? '- (folder) ' : '') + 'depth: ' + itemInfo.depth + ' ' + itemInfo.name;
}
console.log(text);
console.log("End");
});