嵌套执行流控制 [英] Nested Execution Flow Control

查看:59
本文介绍了嵌套执行流控制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经阅读了数十个有关回调,promise和其他控制流的方法的答案,但是显然由于我缺乏能力,我仍然无法解决这个问题.

I've read tens of answers related to callbacks, promises and other ways to control flow, but I can't still wrap my head around this task, obviously due to my lack of competence.

我有一个嵌套的问题:

  1. test_1()(和其他函数)中,我想确保根据元素在对象中的顺序将行添加到表中;
  2. 我只想在test_1完全完成后才执行test_2或test_3(或两者都执行).实际上,正确的序列只会在运行时才知道(会有一个带有可能序列的开关,例如1,2,3或1,3,2或1,2,1,3或1,3,3,2,等等...)
  1. In test_1() (and the other functions) I would like to ensure that the rows are added to the table according to the order in which the elements are in the object;
  2. I would like to execute either test_2 or test_3 (or both after each other) only after test_1 has finished completely. Actually the right sequence will only be known at runtime (there will be a switch with the possible sequences, like 1,2,3 or 1,3,2 or 1,2,1,3 or 1,3,3,2, etc...)

代码:

$(function () {

        // create table
        tbl = document.createElement('table');
        tbl.className = "mainTbl";
        $("body").append(tbl);    

    });

    function test_1() {
            $.each(obj, function () {
                var img = new Image();

                img.onload = function () {
                    // add row of data to table
                    var row = tbl.insertRow(-1);
                    var c1 = row.insertCell(0);
                    c1.innerHTML = "loaded";
                };

                img.onerror = function () {
                    // add row of data to table
                    var row = tbl.insertRow(-1);
                    var c1 = row.insertCell(0);
                    c1.innerHTML = "not loaded";
                };

                img.src = this.url;
            });
    }

function test_2() {
            $.each(obj, function () {
                var img = new Image();

                img.onload = function () {
                    // add row of data to table
                    var row = tbl.insertRow(-1);
                    var c1 = row.insertCell(0);
                    c1.innerHTML = "loaded";
                };

                img.onerror = function () {
                    // add row of data to table
                    var row = tbl.insertRow(-1);
                    var c1 = row.insertCell(0);
                    c1.innerHTML = "not loaded";
                };

                img.src = this.url;
            });
    }
function test_3() {
            $.each(obj, function () {
                var img = new Image();

                img.onload = function () {
                    // add row of data to table
                    var row = tbl.insertRow(-1);
                    var c1 = row.insertCell(0);
                    c1.innerHTML = "loaded";
                };

                img.onerror = function () {
                    // add row of data to table
                    var row = tbl.insertRow(-1);
                    var c1 = row.insertCell(0);
                    c1.innerHTML = "not loaded";
                };

                img.src = this.url;
            });
    }

我知道按顺序调用函数是行不通的,因为它们不会彼此等待...我认为保证可以走了,但我找不到正确的组合,文档也是如此我的技能很复杂.

I know that calling the functions in sequence doesn't work as they don't wait for each other... I think promises are they way to go but I can't find the right combination and the documentation is way too complex for my skills.

构造代码以便按正确顺序执行的最佳方法是什么?

What's the best way to structure the code so that it's executed in the right order?

推荐答案

您已经使这个问题很难回答,因为您的代码是如此抽象,并且缺少大量相关细节,例如如何调用test_1()test_2()等...,您在处理图像,obj是什么,等等...我知道您尝试通过省略细节来简化操作,但实际上您只是太抽象了,以至于不知道如何回答或您真正要解决的问题.

You've made this question very difficult to answer because your code is so abstract and tons of relevant details are missing such as how you call test_1() and test_2(), etc..., what you're doing with the images, what obj is, etc... I know you tried to simplify things by leaving out detail, but really you just made it too abstract to know how to answer or what problem you're really trying to solve.

在JS中,您不能调用某些内容并告诉它等待其他操作完成.您可以告诉test_2()完成test_1()的时间.或者,您可以注册一个函数序列,任何test_n()完成后,它都可以调用序列中的下一个函数.或者,您可以切换为使用Promise并使用Promise功能安排异步事物按顺序运行.

In JS, you can't call something and tell it to wait until something else is done. You can tell test_2() when test_1() is done. Or, you can register a sequence of functions and any time any test_n() is done, it can call the next function in the sequence. Or, you could switch to using promises and use the promise functionality for scheduling async things to run in sequence.

本着抽象讨论的精神,这是一种对事物进行排序的抽象方法.我做了两个主要更改:

In the spirit of your abstract discussion, here's an abstract way of sequencing things. I've made two main changes:

  1. 在迭代obj时同步添加行和单元格,以确保按正确的顺序添加它们.

  1. The rows and cells are added synchronously as you iterate the obj so that guarantees that they are added in the proper order.

已安排了单独的功能,并且只有在已计划所有功能之前,才调用test_2().通过创建一系列功能列表,然后让每个功能使用seq.increment()seq.decrement()来让音序器跟踪完成的时间,以便可以调用下一个功能.

The separate functions are scheduled and test_2() isn't called until all functions scheduled before it have finished. This is orchestrated without calling specific function names by creating a sequenced list of functions and then having each function use seq.increment() and seq.decrement() to let the sequencer keep track of when it's done so the next function can be called.

我的猜测是实际的实现不一定非要通用,更具体的解决方案可能会更简单,但是由于您将讨论保持在非常抽象的状态,因此这是一种按顺序插入行的特定方法还有一种确保函数被依次调用且test_2()直到所有图像都从test_1()完成后才被调用的抽象方法.

My guess is that an actual implementation doesn't have to be this generic and a more specific solution could be simpler, but since you've kept the discussion very abstract, this is a specific way to get the rows inserted in order and an abstract way to make sure the functions are called in order and test_2() isn't called until all the images have finished from test_1().

// an object to maintain a list of functions that can be called in sequence
// and to manage a completion count for each one
function Sequencer() {
    this.list = [];
    this.cnt = 0;
}

Sequencer.prototype.add = function(/* list of function references here */) {
    this.list.push.apply(this.list, arguments);
}

Sequencer.prototype.next = function() {
    var fn = this.list.shift();
    if (fn) {
        fn(this);
    }
}

Sequencer.prototype.increment = function(n) {
    n = n || 1;
    this.cnt += n;
}

// when calling .decrement(), if the count gets to zero
// then the next function in the sequence will be called
Sequencer.prototype.decrement = function(n) {
    n = n || 1;
    this.cnt -= n;
    if (this.cnt <= 0) {
        this.cnt = 0;
        this.next();
    }
}

// your actual functions using the sequencer object
function test_1(seq) {
    seq.increment();
    $.each(obj, function () {
        seq.increment();
        var img = new Image();
        var row = tbl.insertRow(-1);
        var c1 = row.insertCell(0);

        img.onload = function () {
            // add row of data to table
            c1.innerHTML = "loaded";
            seq.decrement();
        };

        img.onerror = function () {
            // add row of data to table
            c1.innerHTML = "not loaded";
            seq.decrement();
        };

        img.src = this.url;
    });
    seq.decrement();
}

function test_2(seq) {
    seq.increment();
    $.each(obj, function () {
        seq.increment();
        var img = new Image();
        var row = tbl.insertRow(-1);
        var c1 = row.insertCell(0);

        img.onload = function () {
            // add row of data to table
            c1.innerHTML = "loaded";
            seq.decrement();
        };

        img.onerror = function () {
            // add row of data to table
            c1.innerHTML = "not loaded";
            seq.decrement();
        };

        img.src = this.url;
    });
    seq.decrement();
}

function test_3(seq) {
    seq.increment();
    $.each(obj, function () {
        seq.increment();
        var img = new Image();
        var row = tbl.insertRow(-1);
        var c1 = row.insertCell(0);

        img.onload = function () {
            // add row of data to table
            c1.innerHTML = "loaded";
            seq.decrement();
        };

        img.onerror = function () {
            // add row of data to table
            c1.innerHTML = "not loaded";
            seq.decrement();
        };

        img.src = this.url;
    });
    seq.decrement();
}

// code to run these in sequence
var s = new Sequencer();

// add all the functions to the sequencer
s.add(test_1, test_2, test_3);

// call the first one to initiate the process
s.next();

仅供参考,我个人永远不会拥有代码test_1,test_2和test_3,它们看起来几乎一样,因为我会将其分解为可以传递参数的通用片段,但是您已经制作了这个摘要,所以我不知道如何考虑您未提供任何差异或细节的内容.

FYI, I would personally never have code test_1, test_2 and test_3 that looks so nearly identical as I would factor it into a common piece that I could pass arguments to, but you've made this abstract so I don't know how to factor something you haven't provided any differences or specifics on.

这篇关于嵌套执行流控制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆