2017-08-15 46 views
1

我需要从上到下搜索整个DOM,以处理每个节点。当一个节点符合某些标准时,我需要同步处理关于该节点的信息,这意味着在处理工作完成之前,我不会继续到DOM中的下一个节点。从使用Promises在循环中执行异步调用的客户端调用生成器函数

节点的处理涉及多个Ajax调用,我想异步执行这些调用。只有在所有ajax调用完成后,最终处理工作才能完成,并且结果返回到我的DOM爬行中。

我所倾向的解决方案是创建一个生成器函数,用于执行DOM爬行,然后在满足条件的节点并且该节点的内容被传回客户端时执行yield语句(通过yield语句)调用下一个函数。

启动对生成器函数的调用的客户端将解析节点的数据,创建多个Promise并与Promise.all()异步执行所有这些promise。

一旦所有的承诺都已完成并且处理完成后,再次调用生成器函数,但是这次来自客户端的处理后的数据返回到yield语句停止的位置,然后该语句将合并到DOM中。

我不清楚的是如何创建执行节点处理的客户端代码,其中包括执行承诺。如果可能,我想避免递归调用客户端函数。下面是一些伪代码,我能想象做:

发电机:

function *crawlDOM() { 
    let node = "html"; 

    function processNode(node) { 
    if (node.value == "someCriteria") { 
     let processedValue = yield node.value; 
     // Do something with the processed value... 
    } 

    for (let i = 0; i < node.children.length; i++) { 
     processNode(node.children[i]); 
    } 
    } 
} 

节点处理客户端:

function processNodeData() { 
    var crawler = crawlDOM(); 
    var processedData = ""; 

    while (true) { 
     var nodeData = crawler.next(processedData).value; 
     var items[] = nodeData.split("\n"); 
     var promises[] = [items.length]; 

     for (let i = 0; i < items.length; i++) { 
      promises[i] = new Promise(function (resolve, reject) { 
      // Do some work 
      resolve(result); 
      } 
     } 

     Promises.all(promises) 
     .then(function(result) { 
      processedData = "some new data"; 
      // Do some final processing. 
      // At this point, we need to call the generator function again but with the processed data. 
      // But this is the wrong place to do it because the "while" loop will have already moved on 
      // to the next node while this "then" code is being executed. 
     }) 

    } 
} 

如何解决这个循环的问题,以便下一次调用发电机函数只发生在Promise.all()完成后?

+0

你使用节点吗?有完整的lib,'npm install co' GH repo在这里..看看=> https://github.com/tj/co –

+0

@KresimirPendic感谢您的链接,但代码似乎已过时,并没有看到承诺将近一年。我在下面提出的解决方案非常简单,解决了这个问题。 – AndroidDev

回答

0

的关键在于在一个循环中执行的承诺是将一个异步函数内部这些承诺:

function processNode(x) { 
    return new Promise(resolve => { 
     setTimeout(() => { 
      resolve(x); 
     }, 2000); 
    }); 
} 

async function startNodeProcessing() { 
    while(true) { 
     var a = processNode(20); 
     var b = processNode(30); 
     var r = await a + await b; 
    } 

    return; 
} 
startNodeProcessing(); 

的代码行:

var r = await a + await b; 

块,直到所有的承诺已经完成。这意味着你不需要Promise.all,尽管你可能仍然可以使用它。阻塞完成后,您可以继续重复该循环。没有递归调用,并且阻塞是异步函数的本地特性,这意味着您没有阻塞主线程,所以如果您要在循环中处理冗长的代码,则不会看到任何UI问题。