简体   繁体   English

在返回promise的函数中调用递归回调

[英]calling recursive callback within function returning promise

I've got a function that appends nodes to the dom and if the node is a script tag with "src" attribute it will set an eventlistener for the "load" event and the callback is the same function so when the js tag will finish executing the same function will be called again and continue to append the nodes exactly where it left of (using document fragment) pseudo code example: 我有一个将节点追加到dom的函数,如果该节点是具有“ src”属性的脚本标记,它将为“ load”事件设置一个事件监听器,并且回调函数是相同的函数,因此当js标记完成时执行相同功能的函数将再次被调用,并继续将节点精确地附加到(使用文档片段)伪代码示例的左边:

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();

Now I've got another func the "main" one which executes this func. 现在,我有了另一个执行该功能的“主要”功能。 and I'm using "then" to continue execution after the appender func has finished. 并且我在appender功能完成后使用“然后”继续执行。 pseudo code example: 伪代码示例:

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
})})

the problem is that if the fragment contains a script tag with src the function will just return; 问题是,如果该片段包含带有src的脚本标签,则该函数将仅返回; and not return a promise so I'm getting 并没有兑现承诺,所以我得到了

" Cannot read property 'then' of undefined ", Cannot read property 'then' of undefined

but I need to use return in order to exit the function and wait for the callback to execute it again and continue appending from the same spot, and only after it finishes appending every node than the promise should return and the ".then()" should be executed. 但是我需要使用return来退出该函数,并等待回调再次执行它,并从同一位置继续追加,并且仅在完成追加每个节点之后,promise应该返回,并且“ .then()”应该执行。 any ideas? 有任何想法吗?

Taken from mozzila's MDN : 取自mozzila的MDN:

A Promise object is created using the new keyword and its constructor. 使用new关键字及其构造函数创建Promise对象。 This constructor takes as its argument a function, called the "executor function". 该构造函数将一个称为“执行程序函数”的函数作为其参数。 This function should take two functions as parameters. 此函数应采用两个函数作为参数。 The first of these functions (resolve) is called when the asynchronous task completes successfully and returns the results of the task as a value. 当异步任务成功完成并返回任务结果作为值时,将调用这些函数中的第一个(解析)。 The second (reject) is called when the task fails, and returns the reason for failure, which is typically an error object. 当任务失败时,将调用第二个(拒绝),并返回失败原因,通常是一个错误对象。

Accompanied by this code example: 伴随以下代码示例:

const myFirstPromise = new Promise((resolve, reject) => {
// do something asynchronous which eventually calls either:
//
//   resolve(someValue); // fulfilled
// or
//   reject("failure reason"); // rejected
});

So how does this apply to your question: 那么这如何适用于您的问题:

You want to interrupt a promise chain if you run into a script tag, in which case you want to wait for it to load first, before continuing to go down the chain. 如果遇到脚本标记,您想中断一个promise链,在这种情况下,您要先等待其加载,然后再继续向下链。 In order to do this, you need to change your code a bit. 为此,您需要稍微更改代码。

if(scriptwithsrc){
  node.addeventlistener("load",appender.bind(this));
  parentnode.appendchild(node);
  return; //This line here is the problem
}

The above code is taken from your post and is being run synchronously, and what you are doing is, you are returning no value. 上面的代码是从您的帖子中获取的,并且正在同步运行,并且您正在做的是,您没有返回任何值。 Since you do not return a promise, your function cannot be used in a then-able promise chain. 由于不返回承诺,因此无法在随后可用的承诺链中使用您的函数。 What you need to do instead is this: 您需要做的是:

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
}

Once the script tag loads, it will trigger the res function which will resolve the promise and your chain will continue. 脚本标签加载后,将触发res函数,该函数将解析promise,并且您的链将继续。 In this particular case the something asynchronous part of the mozzila's code example refers to the loading of your script tag. 在这种特殊情况下,mozzila的代码示例中的某些异步部分涉及脚本标记的加载。

EDIT: Since it was not very clear from the initial post, and was later clarified in the comments, the chain needs to continue from whence it stopped in the current fragment, so as per request a working example was added to reflect this. 编辑:由于从最初的帖子来看不是很清楚,后来在注释中得到了澄清,因此该链需要从它在当前片段中停止的位置开始继续,因此应要求添加了一个工作示例以反映这一点。

Working example: 工作示例:

 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(); 

only after it finishes appending every node than the promise should return 只有在完成每个节点的追加之后,诺言才应返回

No, you will need to create and return the promise immediately. 不,您需要立即创建并返回承诺。 The promise should be fulfilled when you are done appending all nodes. 完成附加所有节点后,应兑现承诺。 So you would write 所以你会写

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();
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM