为什么我的 Promise Chain 不能以这种嵌套方式工作?
Why does my Promise Chain not work in this nested way?
我想像这样在 Promise 链中链接 4 个函数:
函数 1 -> 函数 2 -> 函数 3 -> 函数 4
我的无极链
if ($location.$$url !== "/dashboard") {
vm.customURL = true;
// (1) Set root vars & Rebuild tickerTagsContainer:
var promise = TagFactory.buildUrlObject($location.$$url).then(function() {
console.log('TagFactory.buildUrlObject PROMISE returned');
}).then(function() {
console.log('(2) Re-display tags in viewHeader');
// (2) Re-display tags in viewHeader:
viewHeader = ScopeFactory.getScope('viewHeader');
viewHeader.vh.displayViewHeaderTags().then(function() {
console.log('viewHeader.vh.displayViewHeaderTags FINISHED!');
});
}).then(function() {
// (3) Reselect timeSpan:
console.log('(3) Reselect timeSpan');
viewHeader.vh.toggleTimeSpan(vm.timeSpan);
// (4) Refresh URL:
console.log('(4) Refresh URL');
ViewFactory.remakeViewObject($location.$$url);
});
}
结果console.logs:
^ 注意我从来没有看到这个日志:
viewHeader.vh.displayViewHeaderTags().then(function() {
console.log('viewHeader.vh.displayViewHeaderTags FINISHED!');
});
理想情况下,我想将我的 (3) 函数放在其中,然后像这样链接我的 (4):
viewHeader.vh.displayViewHeaderTags().then(function() {
console.log('viewHeader.vh.displayViewHeaderTags FINISHED!');
console.log('(3) Reselect timeSpan');
viewHeader.vh.toggleTimeSpan(vm.timeSpan).then(function() {
console.log('(4) Refresh URL');
ViewFactory.remakeViewObject($location.$$url);
});
});
但是我从来没有从 .then
函数中看到 displayViewHeaderTags
的 console.log
这是我的 displayViewHeaderTags
的样子:
function displayViewHeaderTags() {
vm.viewTickerTags = [];
vm.viewTickerTags = TagFactory.retrieveTickerTags('all');
var deferred = $q.defer();
var tikObjs = vm.viewTickerTags.map(function(el) { return el.ticker; });
var tagObjs = vm.viewTickerTags.map(function(el) { return el.tags; });
var tags = _.flatten(tagObjs);
// forEach loops up to 3 times:
tags.forEach(function(tag, i) {
vm.viewTags = [];
ApiFactory.getTagDataSilm(tag.term_id).then(function(data) {
vm.viewTags.push(data.data.ticker_tag);
if (i === tags.length) {
deferred.resolve();
}
});
});
return deferred.promise;
}
在我的 displayViewHeaderTags
函数中,我打了一个循环,该循环将 运行 最多 3 次,在完成获取数据后,它将填满数组然后调用 deffered.resolve
。然后 returns 它 return deferred.promise;
那么为什么我从来没有看到这个日志? console.log('viewHeader.vh.displayViewHeaderTags FINISHED!');
你的链并没有真正做任何事情,因为你没有从任何这些匿名函数返回承诺。您看不到该日志可能是因为 ApiFactory.getTagDataSilm
失败或从未解决。尝试将错误处理程序添加到您的流程中。
if ($location.$$url !== "/dashboard") {
vm.customURL = true;
// (1) Set root vars & Rebuild tickerTagsContainer:
var promise = TagFactory.buildUrlObject($location.$$url).then(function() {
console.log('TagFactory.buildUrlObject PROMISE returned');
}).then(function() {
console.log('(2) Re-display tags in viewHeader');
// (2) Re-display tags in viewHeader:
viewHeader = ScopeFactory.getScope('viewHeader');
return viewHeader.vh.displayViewHeaderTags().then(function() {
console.log('viewHeader.vh.displayViewHeaderTags FINISHED!');
});
}).then(function() {
// (3) Reselect timeSpan:
console.log('(3) Reselect timeSpan');
return viewHeader.vh.toggleTimeSpan(vm.timeSpan);
}).then(function() {
// (4) Refresh URL:
console.log('(4) Refresh URL');
return ViewFactory.remakeViewObject($location.$$url);
}).catch(function(error) {
console.log('Something failed', error);
});
}
在 displayViewHeaderTags
内,您可以使用 $q.all
,以便为您处理拒绝:
// forEach loops up to 3 times:
vm.viewTags = [];
return $q.all(_.map(tags, function(tag) {
return ApiFactory.getTagDataSilm(tag.term_id).then(function(data) {
vm.viewTags.push(data.data.ticker_tag);
});
}));
你的 i 永远不会与长度相同,因为 i 变量从零开始(数组索引从零开始)。这意味着如果你有一个长度为 2 的数组,你的 i 值将分别为 0 和 1。它永远不会等于零。基本上,您希望条件为:
vm.viewTags.push(data.data.ticker_tag);
if (i + 1 === tags.length) {
deferred.resolve();
}
无论如何,使用defer()
是code smell。
一种更优雅的方法是使用 $q.all
var allPromises = [];
var promise;
tags.forEach(function(tag) {
vm.viewTags = [];
promise = ApiFactory.getTagDataSilm(tag.term_id).then(function(data) {
vm.viewTags.push(data.data.ticker_tag);
});
// Create an array of promises, one promise for each request
allPromises.push( promise );
});
// Return a new promise that will only be resolved
// when all the promises of the array `allPromises` are resolved,
// or is rejected when one of them is.
return $q.all( allPromises );
我想像这样在 Promise 链中链接 4 个函数:
函数 1 -> 函数 2 -> 函数 3 -> 函数 4
我的无极链
if ($location.$$url !== "/dashboard") {
vm.customURL = true;
// (1) Set root vars & Rebuild tickerTagsContainer:
var promise = TagFactory.buildUrlObject($location.$$url).then(function() {
console.log('TagFactory.buildUrlObject PROMISE returned');
}).then(function() {
console.log('(2) Re-display tags in viewHeader');
// (2) Re-display tags in viewHeader:
viewHeader = ScopeFactory.getScope('viewHeader');
viewHeader.vh.displayViewHeaderTags().then(function() {
console.log('viewHeader.vh.displayViewHeaderTags FINISHED!');
});
}).then(function() {
// (3) Reselect timeSpan:
console.log('(3) Reselect timeSpan');
viewHeader.vh.toggleTimeSpan(vm.timeSpan);
// (4) Refresh URL:
console.log('(4) Refresh URL');
ViewFactory.remakeViewObject($location.$$url);
});
}
结果console.logs:
^ 注意我从来没有看到这个日志:
viewHeader.vh.displayViewHeaderTags().then(function() {
console.log('viewHeader.vh.displayViewHeaderTags FINISHED!');
});
理想情况下,我想将我的 (3) 函数放在其中,然后像这样链接我的 (4):
viewHeader.vh.displayViewHeaderTags().then(function() {
console.log('viewHeader.vh.displayViewHeaderTags FINISHED!');
console.log('(3) Reselect timeSpan');
viewHeader.vh.toggleTimeSpan(vm.timeSpan).then(function() {
console.log('(4) Refresh URL');
ViewFactory.remakeViewObject($location.$$url);
});
});
但是我从来没有从 .then
函数中看到 displayViewHeaderTags
console.log
这是我的 displayViewHeaderTags
的样子:
function displayViewHeaderTags() {
vm.viewTickerTags = [];
vm.viewTickerTags = TagFactory.retrieveTickerTags('all');
var deferred = $q.defer();
var tikObjs = vm.viewTickerTags.map(function(el) { return el.ticker; });
var tagObjs = vm.viewTickerTags.map(function(el) { return el.tags; });
var tags = _.flatten(tagObjs);
// forEach loops up to 3 times:
tags.forEach(function(tag, i) {
vm.viewTags = [];
ApiFactory.getTagDataSilm(tag.term_id).then(function(data) {
vm.viewTags.push(data.data.ticker_tag);
if (i === tags.length) {
deferred.resolve();
}
});
});
return deferred.promise;
}
在我的 displayViewHeaderTags
函数中,我打了一个循环,该循环将 运行 最多 3 次,在完成获取数据后,它将填满数组然后调用 deffered.resolve
。然后 returns 它 return deferred.promise;
那么为什么我从来没有看到这个日志? console.log('viewHeader.vh.displayViewHeaderTags FINISHED!');
你的链并没有真正做任何事情,因为你没有从任何这些匿名函数返回承诺。您看不到该日志可能是因为 ApiFactory.getTagDataSilm
失败或从未解决。尝试将错误处理程序添加到您的流程中。
if ($location.$$url !== "/dashboard") {
vm.customURL = true;
// (1) Set root vars & Rebuild tickerTagsContainer:
var promise = TagFactory.buildUrlObject($location.$$url).then(function() {
console.log('TagFactory.buildUrlObject PROMISE returned');
}).then(function() {
console.log('(2) Re-display tags in viewHeader');
// (2) Re-display tags in viewHeader:
viewHeader = ScopeFactory.getScope('viewHeader');
return viewHeader.vh.displayViewHeaderTags().then(function() {
console.log('viewHeader.vh.displayViewHeaderTags FINISHED!');
});
}).then(function() {
// (3) Reselect timeSpan:
console.log('(3) Reselect timeSpan');
return viewHeader.vh.toggleTimeSpan(vm.timeSpan);
}).then(function() {
// (4) Refresh URL:
console.log('(4) Refresh URL');
return ViewFactory.remakeViewObject($location.$$url);
}).catch(function(error) {
console.log('Something failed', error);
});
}
在 displayViewHeaderTags
内,您可以使用 $q.all
,以便为您处理拒绝:
// forEach loops up to 3 times:
vm.viewTags = [];
return $q.all(_.map(tags, function(tag) {
return ApiFactory.getTagDataSilm(tag.term_id).then(function(data) {
vm.viewTags.push(data.data.ticker_tag);
});
}));
你的 i 永远不会与长度相同,因为 i 变量从零开始(数组索引从零开始)。这意味着如果你有一个长度为 2 的数组,你的 i 值将分别为 0 和 1。它永远不会等于零。基本上,您希望条件为:
vm.viewTags.push(data.data.ticker_tag);
if (i + 1 === tags.length) {
deferred.resolve();
}
无论如何,使用defer()
是code smell。
一种更优雅的方法是使用 $q.all
var allPromises = [];
var promise;
tags.forEach(function(tag) {
vm.viewTags = [];
promise = ApiFactory.getTagDataSilm(tag.term_id).then(function(data) {
vm.viewTags.push(data.data.ticker_tag);
});
// Create an array of promises, one promise for each request
allPromises.push( promise );
});
// Return a new promise that will only be resolved
// when all the promises of the array `allPromises` are resolved,
// or is rejected when one of them is.
return $q.all( allPromises );