我已经阅读了数十个与回调、 promise 和其他控制流程的方法相关的答案,但我仍然无法专注于这项任务,显然是因为我缺乏能力。
我有一个嵌套问题:
- 在
test_1()
(以及其他函数)中,我想确保根据元素在对象中的顺序将行添加到表中; - 我想仅在 test_1 完全完成后执行 test_2 或 test_3(或依次执行)。实际上,正确的序列只有在运行时才知道(会有一个带有可能序列的开关,例如 1,2,3 或 1,3,2 或 1,2,1,3 或 1,3,3,2,等等...)
代码:
$(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;
});
}
我知道按顺序调用函数是行不通的,因为它们不互相等待...我认为 Promise 是可行的方法,但我找不到正确的组合,而且文档也太糟糕了我的技能很复杂。
构建代码以便以正确的顺序执行的最佳方法是什么?
最佳答案
您使这个问题变得非常难以回答,因为您的代码非常抽象,并且缺少大量相关细节,例如您如何调用 test_1()
和 test_2()
等...,您正在对图像做什么,obj
是什么,等等...我知道您试图通过省略细节来简化事情,但实际上您刚刚做到了太抽象,不知道如何回答或您真正想解决什么问题。
在 JS 中,你不能调用某些东西并告诉它等待其他事情完成。您可以告诉 test_2()
test_1()
何时完成。或者,您可以注册一系列函数,并且每当完成任何 test_n()
时,它都可以调用该序列中的下一个函数。或者,您可以切换到使用 Promise 并使用 Promise 功能来安排异步事物按顺序运行。
本着抽象讨论的精神,这是一种对事物进行排序的抽象方法。我做了两个主要更改:
当您迭代
obj
时,行和单元格会同步添加,以保证它们按正确的顺序添加。单独的函数已被调度,并且只有在所有函数都已调度完成之前才会调用
test_2()
。这是通过创建函数的排序列表,然后让每个函数使用 seq.increment() 和 seq.decrement() 来让排序器在不调用特定函数名称的情况下进行编排的跟踪它何时完成,以便可以调用下一个函数。
我的猜测是,实际的实现不必如此通用,更具体的解决方案可能会更简单,但由于您将讨论保持得非常抽象,所以这是一种按顺序插入行的特定方法以及一种抽象方法,以确保按顺序调用函数,并且在 test_1()
中的所有图像完成之前不会调用 test_2()
。
// 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,因为我会将其分解为一个可以传递参数的通用片段,但你已经做了这个抽象,所以我不知道如何考虑您未提供任何差异或细节的内容。
关于javascript - 嵌套执行流程控制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23925578/