我有以下代码:
function load(lab, el) {
return Promise.all([Util.loadHtml(lab), Util.loadScript(lab)])
.then(function(responses) {
parse(responses[0], el, responses[1]);
});
}
function parse(html, parent, context) {
var children = [].slice.call(html.childNodes).filter(function (item) { return item.nodeType === 1 || item.nodeType === 3; });
for (var i = 0; i < children.length; i++) {
var child = children[i];
if (child.tagName.indexOf('-') >= 0) {
load(child.tagName.toLowerCase(), parent);
}
else {
var parsedNode = parseNode(child, context);
parent.appendChild(parsedNode);
if (child.hasChildNodes())
parse(child, parsedNode, context);
}
}
}
基本上,这应该是它应该做的:
load
函数,该函数将导入两个文件,一个html
和一个js
,当这些请求的承诺完成后,它会调用一个名为parse
的函数,它将循环到HTML中,并将使用JS文件中声明的类解析一些字符串。<my-element>
,然后,它会尝试加载my-element.html
和my-element.js
,然后它会在该HTML内部循环太问题
由于load
函数返回一个promise,而我正在同步调用它,它会立即返回,因此,子项不会放在正确的父项中。
例如,如果我在C#中执行此操作,或使用ES7 async
和await
关键字,那将非常简单。但我不知道如何异步调用load
函数。任何猜测?
答案 0 :(得分:3)
如果函数是异步的,它应该返回一个promise。总是。甚至(或者:尤其)在then
回调中。
如果您在该循环中产生多个承诺,则可以通过Promise.all
:
function load(lab, el) {
return Promise.all([Util.loadHtml(lab), Util.loadScript(lab)])
.then(function(responses) {
return parse(responses[0], el, responses[1]);
// ^^^^^^
});
}
function parse(html, parent, context) {
var children = [].slice.call(html.childNodes).filter(function (item) { return item.nodeType === 1 || item.nodeType === 3; });
return Promise.all(children.map(function(child, i) {
//^^^^^^^^^^^^^^^^^^
if (child.tagName.indexOf('-') >= 0) {
return load(child.tagName.toLowerCase(), parent);
// ^^^^^^
} else {
var parsedNode = parseNode(child, context);
parent.appendChild(parsedNode);
if (child.hasChildNodes())
return parse(child, parsedNode, context);
// ^^^^^^
}
}));
}
如果我在C#中执行此操作,或者使用ES7 async和await关键字,那将非常简单。但我不知道如何异步调用
load
函数
是的,你真的应该考虑使用它们。或者您可以使用ES6生成器函数和运行器(由许多流行的promise库提供)来模拟它们。但无论如何你都在使用转换器,对吗?
写load
对他们来说很容易:
async function load(lab, el) {
var responses = await Promise.all([Util.loadHtml(lab), Util.loadScript(lab)]);
return parse(responses[0], el, responses[1]);
}
答案 1 :(得分:1)
您可以使用.reduce来实现:
$form = $this->get('form.factory')->createNamedBuilder('your-custom-name', 'form', null, array(
'constraints' => $collectionConstraint,
))
->add('delete', 'submit')
->getForm();
然后,当通过孩子的角蛋白时,它会继续链接承诺,每个孩子可以独立加载或解析,直到所有孩子都得到解决,从function load(lab, el) {
return Promise.all([Util.loadHtml(lab), Util.loadScript(lab)])
.then(function(responses) {
return parse(responses[0], el, responses[1]);
});
}
function parse(html, parent, context) {
var children = [].slice.call(html.childNodes).filter(function (item) { return item.nodeType === 1 || item.nodeType === 3; });
// What this return is a promise chained through all of its children
// So until all children get resolved, this won't get resolved.
return children.reduce(function(promise, child, idx) {
var childPromise = null;
if (child.tagName.indexOf('-') >= 0) {
// Start to load the contents, until childPromise is resolved, the final
// can't be resolved.
childPromise = load(child.tagName.toLowerCase(), parent);
} else {
var parsedNode = parseNode(child, context);
parent.appendChild(parsedNode);
// If it has child, also make it return a promise which will be resolved
// when child's all children parsed.
if (child.hasChildNodes()) {
childPromise = parse(child, parsedNode, context);
}
}
// It's either null, which means it'll be resolved immediately,
// or a promise, which will wait until its childs are processed.
return promise.then(function() {
return childPromise;
});
}, Promise.resolve());
}
返回的承诺得到解决。所以你现在可以使用它:
parse
编辑:正如Bergi所暗示的那样,Promise.all比.reduce更好,因为它会在任何一个孩子(孙子女)失败时立即拒绝。在发布The more acceptable answer时,我只是给它一个链接,而不是添加parse(THE PARAM OF ROOT).then(function() {
// All the big parents's children are now parsed.
console.log('All done');
});
版本。
而且JavaScript Promises#chaining也可以帮到你。
答案 2 :(得分:0)
我认为这是你弄错了:
if (child.tagName.indexOf('-') >= 0) {
load(child.tagName.toLowerCase(), parent);
}
您正在将parent
对象的child
传递给parent
对象的grandchild
。您可能需要将child
作为grandchild
的父级传递。
答案 3 :(得分:0)
最后,它比我想象的要简单:
function load(lab, el) {
return Promise.all([Util.loadHtml(lab), Util.loadScript(lab)])
.then(function(responses) {
return parse(responses[0], el, responses[1]); // return here
});
}
function parse(html, parent, context) {
var children = [].slice.call(html.childNodes).filter(function (item) { return item.nodeType === 1 || item.nodeType === 3; });
for (var i = 0; i < children.length; i++) {
var child = children[i];
if (child.tagName.indexOf('-') >= 0) {
return load(child.tagName.toLowerCase(), parent); // return here
}
else {
var parsedNode = parseNode(child, context);
parent.appendChild(parsedNode);
if (child.hasChildNodes())
parse(child, parsedNode, context);
}
}
}
由于我的解析必须是同步的(因为订单等),我唯一需要的是等待load
函数完成后再回到parse
,我改变的唯一的事情是的,而不是直接调用parse
内的load
函数,反之亦然,我现在正在使用return
,从那时起它将等待执行,之后回到来电者那里。
其他有用的东西,对我的用例来说甚至更好:我最终创建了我的自定义元素的克隆,并将其附加到父级,调用load函数传递它。这样做,我可以加载它的所有子异步,而不会没有附加到DOM。
执行速度更快,可读性更高!