如何将bluebird promises应用于我现有的javascript遍历和基于递归的逻辑?

时间:2016-12-01 17:16:29

标签: javascript asynchronous promise traversal bluebird

我很想知道如何在我现有的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) {

    });

我怎么能用蓝鸟做到这一点?

1 个答案:

答案 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) { … });