我很想知道如何在我现有的javascript代码中使用bluebird promises,这些代码利用了大量基于回调的机制。这是场景:
在我使用jQuery加载页面的web应用程序中,我将获取页面的主菜单链接并从中生成TreeModel结构,稍后我将使用它来显示页面顶部的Breadcrumb。 / p>
我用于生成此TreeModel的函数如下:
function _traverseNodeChildren(selector, parentNode, callback1, callback2) {
$(parentNode.model.element).find(selector).each(function(idx, elm) {
// Create a Tree Node using TreeModel
let node = _createTreeNode.apply(this.comp, [elm]);
this.parentNode.addChild(node);
let hasChildren = $(elm).find("+ul.dropdown-menu").length > 0;
if (hasChildren == true)
_traverseNodeChildren.apply(this.comp, ["+ul.dropdown-menu > li > a", node, callback1, callback2]);
if (node.model.id == "aboutLink") // last node
{
setTimeout(() => {
callback1.apply(this.comp, [callback2]);
}, 100);
}
}.bind({parentNode: parentNode, comp: this}));
}
在上面的遍历完成后,我想调用myServerCall
函数,该函数将涉及异步Ajax请求并发布完成此异步请求,最后我想调用第三个函数myFinalFunc
。
目前我正在使用以下代码来执行此遍历代码:
const TreeModel = require('tree-model');
const _treeModel = new TreeModel();
let _bcRoot = _treeModel.parse({
id: "0",
href: null,
text: "",
element: $(".main-menu").get(0)
});
_traverseNodeChildren.apply(this, ["> li > a[data-bc-id]",
_bcRoot, myServerCall, myFinalFunc]);
但我希望将其转换为基于蓝鸟承诺的方法以获得对它的更多控制。
以下是我想要的代码:
_traverseNodeChildren.apply(this, ["> li > a[data-bc-id]", _bcRoot])
.then(function() {
return myServerCall();
})
.then(function() {
return myFinalFunc();
})
.catch(function(error) {
});
我怎么能用蓝鸟做到这一点?
答案 0 :(得分:1)
我首先将您的回调代码简化为
function traverseNodeChildren(comp, selector, parentNode, callback) {
$(parentNode.model.element).find(selector).each(function(_, elm) {
// Create a Tree Node using TreeModel
let node = createTreeNode(comp, elm);
parentNode.addChild(node);
let hasChildren = $(elm).find("+ul.dropdown-menu").length > 0;
if (hasChildren)
_traverseNodeChildren(comp, "+ul.dropdown-menu > li > a", node, callback);
if (node.model.id == "aboutLink")
setTimeout(function() {
callback(comp);
}, 100);
}
});
}
traverseNodeChildren(this, "> li > a[data-bc-id]", _bcRoot, function(comp) {
myServerCall.call(comp, myFinalFunc)
});
但是,考虑到callback
可能被多次调用(当有多个aboutLinks时),你无法真正将其转换为promises。除非你希望它的行为不同。
如果只有一个aboutLink,那么在遍历函数中根本不需要异步和回调。只是做
function traverseNodeChildren(comp, selector, parentNode) {
$(parentNode.model.element).find(selector).each(function(_, elm) {
// Create a Tree Node using TreeModel
let node = createTreeNode(comp, elm);
parentNode.addChild(node);
let hasChildren = $(elm).find("+ul.dropdown-menu").length > 0;
if (hasChildren)
_traverseNodeChildren(comp, "+ul.dropdown-menu > li > a", node);
});
}
traverseNodeChildren(this, "> li > a[data-bc-id]", _bcRoot);
setTimeout(function() {
myServerCall(myFinalFunc)
}, 100);
您现在可以轻松转换为蓝鸟,甚至无需触摸traverseNodeChildren
:
traverseNodeChildren(this, "> li > a[data-bc-id]", _bcRoot);
Promise.delay(100)
.then(myServerCall)
.then(myFinalFunc)
.catch(function(err) { … });
如果您想要在每个节点上等待某种延迟遍历,可以使用
function traverseNodeChildren(comp, selector, parentNode) {
return Promise.mapSeries($(parentNode.model.element).find(selector), function(elm) {
// Create a Tree Node using TreeModel
let node = createTreeNode(comp, elm);
parentNode.addChild(node);
let hasChildren = $(elm).find("+ul.dropdown-menu").length > 0;
if (hasChildren)
return _traverseNodeChildren(comp, "+ul.dropdown-menu > li > a", node);
else
return Promise.delay(100);
});
}
traverseNodeChildren(this, "> li > a[data-bc-id]", _bcRoot)
.then(myServerCall)
.then(myFinalFunc)
.catch(function(err) { … });