问题
Imagine that we have a Sequence
widget which loads Element
widgets and loads some config for each of them (through loadConfig()
) .Schematic view is described on the image below:
The problem is that every approach I tried does the same "bad" thing: it freezes everything until all Elements
are loaded.
array.forEach(elements, function(element) {
element.loadConfig();
});
or
var counter = 0;
var loadConfig = function(element) {
element.loadConfig()
if (++counter <= elements.length - 1) {
loadConfig(elements(counter));
}
};
loadConfig(0);
Is there any way to load and show elements one by one, instead of trying to load everything at once? JavaScript doesn't have multi-threading.. so I am really running out of ideas.
EDIT: Tried to use setTimeout()
as suggested in this great answer Why is setTimeout(fn, 0) sometimes useful?
But this doesn't solve the problem. Looks like Dojo has something that prevents widgets to be rendered one by one - it loads while all data is loaded and then load them all together.
EDIT2: This is how setTimeout()
was tried to be used:
array.forEach(elements, function(element) {
setTimeout(function() {
element.loadConfig();
}, 0);
});
EDIT3: Here is full code what is going on. The hierarchy is: TestSequence > Test > ElementsGroup > Element.
// Inside TestSequence widget:
...
var config = [someConfig1, someConfig2, ... someCondigN]
array.forEach(sequenceConfig, function(sequenceConfigItem, i) {
require(['some_path/' + sequenceConfig.type], function(cls) {
var test = new cls();
test.set('config', sequenceConfigItem);
});
}, this);
...
// Inside Test widget
...
_setConfigAttr: function(testConfig) {
elementsGroup.set('config', testConfig);
},
...
// Inside ElementsGroup widget
...
_setConfigAttr: function(elementsGroupConfig) {
array.forEach(config, function(elemenstGroupConfigItem, i) {
require(['some_path/' + elementsGroupConfigItem.type], function(cls) {
var element = new cls(); // <--- removing this solves the problem
element.set('config', elementsGroupConfigItem);
});
}, this);
},
...
// Inside Element widget
...
_setConfigAttr: function(testConfig) {
// apply simple DOM-stuff - set name, description, etc.
},
...
回答1:
The solution was to use setTimeout
along with recursive function, like this:
var counter = 0;
recursiveFunc: function(element) {
setTimeout(function() {
// Do stuff for element[counter]
if (++counter < numberOfElements) {
recursiveFunc(element);
}
}, 0);
}
recursiveFunc(element[counter])
The UI thread would still be buggy, but at least it is not frozen. This solution was picked as a fast one. For a long-one it was decided to optimize the code to get rid of sync XHR request.
来源:https://stackoverflow.com/questions/33145579/dojo-using-settimeout-to-load-widgets-in-async-way