我有一个将节点附加到dom的函数,如果该节点是具有“ src”属性的脚本标签,它将为“ load”事件设置一个事件监听器,并且回调是相同的函数,因此当js标签将完成执行相同的功能,将再次被调用,并继续将节点精确地附加到其剩余的位置(使用文档片段) 伪代码示例:
'timeout'
现在,我有另一个函数,即执行该函数的“主要”函数。
function appender(){// i'm calling the function with bind so 'this' is my object
while(documentfragment.children.length > 0){
if(scriptwithsrc){
node.addeventlistener("load",appender.bind(this));
parentnode.appendchild(node);
return;
}
//if its not a script tag than just append the node
parentnode.appendchild(node);
return Promise.resolve();
函数完成后,我使用“然后”继续执行。
伪代码示例:
appender
问题是,如果片段包含带有src的脚本标签,该函数将仅返回;而不是兑现承诺,所以我得到
“ let appenderBinder = appender.bind(Myobject);
Myobject.fragment = fragment1;
appenderBinder().then(() => {
//first execution for fragment1 is over lets continue to fragment2
//we call it again but change our object before that
Myobject.fragment = fragment2;
appenderBinder().then(() => {
//some more code
})})
”,
但是我需要使用return来退出该函数,并等待回调再次执行它,并继续从同一位置追加,并且只有在完成追加每个节点之后,promise才应返回,然后返回“ .then ()”应执行。 有什么想法吗?
答案 0 :(得分:2)
取自mozzila的MDN:
使用new关键字及其构造函数创建Promise对象。该构造函数将一个称为“执行程序函数”的函数作为其参数。此函数应采用两个函数作为参数。当异步任务成功完成并返回任务结果作为值时,将调用这些函数中的第一个(解析)。当任务失败时,将调用第二个(拒绝),并返回失败原因,通常是一个错误对象。
伴随以下代码示例:
const myFirstPromise = new Promise((resolve, reject) => {
// do something asynchronous which eventually calls either:
//
// resolve(someValue); // fulfilled
// or
// reject("failure reason"); // rejected
});
那么这如何适用于您的问题:
如果遇到脚本标记,则要中断一个promise链,在这种情况下,您要先等待其加载,然后再继续向下链。为此,您需要稍微更改代码。
if(scriptwithsrc){
node.addeventlistener("load",appender.bind(this));
parentnode.appendchild(node);
return; //This line here is the problem
}
以上代码摘自您的文章,并且正在同步运行,而您正在做的是,您没有返回任何值。由于不返回承诺,因此无法在随后可用的承诺链中使用您的函数。相反,您需要做的是:
if(scriptwithsrc){
let loadingDone = new Promise(function(res, rej){
node.addEventListener("load", res)
parentnode.appendchild(node)
}
return loadingDone; // This line returns the promise as usual
}
else{
parentnode.appendchild(node)
return Promise.resolve() //And so does this line
}
一旦脚本标签加载,它将触发res
函数,该函数将解决诺言,您的链将继续。在这种特殊情况下,mozzila代码示例的异步事物部分涉及脚本标记的加载。
编辑:由于从最初的帖子来看不是很清楚,后来在注释中得到了澄清,因此该链需要从它在当前片段中停止的地方继续,因此根据请求,添加了一个工作示例来反映这一点。
工作示例:
function appender(arg) {
let i;
for (i = 0; i < arg.length; i++) {
if (arg[i].script) {
let chainedPromise;
let pauseProm = new Promise(function (res, rej) {
setTimeout(function () {
console.log('Appended element: ', arg[i].name);
res();
}, 2000); //to mimic script load;
});
let j;
let newChain = [];
for (j = i + 1; j < arg.length; j++) {
newChain.push(arg[j]);
}
chainedPromise = pauseProm.then(function () {
return appender(newChain)
});
return chainedPromise;
} else
console.log('Appended element: ', arg[i].name);
}
return Promise.resolve();
}
function Main() {
appender([
{name: '1', script: false},
{name: '2', script: false},
{name: '3', script: true}
]).then(function () {
appender([
{name: '4', script: false},
{name: '5', script: false},
{name: '6', script: true},
{name: '7', script: true}
]).then(function () {
appender([
{name: '8', script: false},
{name: '9', script: true},
{name: '10', script: false},
{name: '11', script: true},
{name: '12', script: true}
]).then(function () {
console.log('done')
});
});
});
}
Main();
答案 1 :(得分:1)
仅在完成每个节点的追加之后,诺言应返回
否,您将需要立即创建并返回承诺。完成附加所有节点后,应实现承诺。所以你会写
function appender() {
if (documentfragment.children.length > 0){
if (scriptwithsrc) {
const promise = new Promise(resolve => {
// ^^^^^^^^^^^
node.addeventlistener("load", resolve);
// ^^^^^^^
parentnode.appendchild(node);
});
return promise.then(appender.bind(this));
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
} else { // its not a script tag then just append the node
parentnode.appendchild(node);
return appender.call(this); // recurse
}
} else {
return Promise.resolve();
}
}