簡體   English   中英

在返回promise的函數中調用遞歸回調

[英]calling recursive callback within function returning promise

我有一個將節點追加到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();

現在,我有了另一個執行該功能的“主要”功能。 並且我在appender功能完成后使用“然后”繼續執行。 偽代碼示例:

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

問題是,如果該片段包含帶有src的腳本標簽,則該函數將僅返回; 並沒有兌現承諾,所以我得到了

Cannot read property 'then' of undefined

但是我需要使用return來退出該函數,並等待回調再次執行它,並從同一位置繼續追加,並且僅在完成追加每個節點之后,promise應該返回,並且“ .then()”應該執行。 有任何想法嗎?

取自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函數,該函數將解析promise,並且您的鏈將繼續。 在這種特殊情況下,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(); 

只有在完成每個節點的追加之后,諾言才應返回

不,您需要立即創建並返回承諾。 完成附加所有節點后,應兌現承諾。 所以你會寫

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