2017-07-27 131 views
0

我目前正在研究一個項目,在基於lunr.js的JavaScript中實現一個全文搜索客戶端。如何處理異步循環?

事情是,我在建設,然後保存索引掙扎,因爲我有幾個異步調用。

function buildIndex(rawIndex, root, indexPath = root + 'js/app/index.json') { 
    var path = path || require('path'); 
    var fs = fs || require('fs'), 
    promesses = [], 
    ignore = ['node_modules'], 
    files = fs.readdirSync(root); 
    files.forEach(function (file) { 

    if (fs.statSync(path.join(root, file)).isDirectory() && ignore.indexOf(file) == -1) { 
     buildIndex(rawIndex, path.join(root, file), indexPath); 
    } 
    else if (file.substr(-5) === '.html' && file != 'example.html') { 
     var promesse = JSDOM.fromFile(path.join(root, file)).then(dom => { 

     var $ = require('../lib/_jquery')(dom.window); 
     populate(); 
     console.log(file + " indexé"); 
     function populate() { 
      $('h1, h2, h3, h4, h5, h6').each(function() { 
      var title = $(this); 
      var link = path.join(root, file).replace('..\\', '') + "#" + title.prop('id'); 
      var body = title.nextUntil('h1, h2, h3, h4, h5, h6'); 
      rawIndex.add({ 
       id: link, 
       title: title.text().latinise(), 
       body: body.text().latinise() 
      }); 
      }); 
     }; 
     }); 
     promesses.push(promesse); 
    } 
    }); 
    Promise.all(promesses) 
    .then(function() { 
     fs.writeFileSync(indexPath, "var data = " + JSON.stringify(rawIndex), 'utf8'); 
    }) 
    .catch(function (err) { 
     console.log("Failed:", err); 
    }); 
}; 

在此先感謝。

+2

您不在等待遞歸調用的結果 - 它不返回承諾,也不會將其放入數組中。 – Bergi

+0

@DnzzL是'rawIndex.add'的異步調用? –

+0

@Bergi確實。我不知道如何正確實施它。 – DnzzL

回答

0

及如何使用foreach是不是讓一心要返回無極正確的選擇。 因此,使用.map,然後在if/else語句中返回Promises更爲明智。 最後,我們必須調用Promises.all(promise),然後(...)按預期使用。

我的最終功能:

function buildIndex(rawIndex, root, indexPath = root + 'js/app/index.json') { 
    var path = path || require('path'); 
    var fs = fs || require('fs'), 
    promises = [], 
    ignore = ['node_modules'], 
    files = fs.readdirSync(root); 

    var promises = files.map(function (file) { 
    if (fs.statSync(path.join(root, file)).isDirectory() && ignore.indexOf(file) == -1) { 
     return buildIndex(rawIndex, path.join(root, file), indexPath); 
    } 
    else if (file.substr(-5) === '.html' && file != 'example.html') { 
     return JSDOM.fromFile(path.join(root, file)).then(dom => { 

     var $ = require('jquery')(dom.window); 
     populate(); 
     console.log(file + " indexé"); 

     function populate() { 
      $('h1, h2, h3, h4, h5, h6').each(function() { 
      var title = $(this); 
      var link = path.join(root, file).replace('..\\', '') + "#" + title.prop('id'); 
      var body = title.nextUntil('h1, h2, h3, h4, h5, h6'); 
      rawIndex.add({ 
       id: link, 
       title: title.text().latinise(), 
       body: body.text().latinise() 
      }); 
      }); 
     }; 
     }) 
    } 
    }) 
    return Promise.all(promises).then(function() { 
    fs.writeFileSync(indexPath, "var data = " + JSON.stringify(rawIndex), 'utf8'); 
    }); 
}; 

感謝@Bergi的回答和那些誰幫助。

0

有四個方面的問題:

  • 你的功能buildIndexreturn的承諾,所以調用它時
  • 當遇到一個目錄,你叫buildIndex遞歸但不要一個不能等待結果嘗試等待其結果,就像您在其他情況下使用promesse所做的一樣。
  • 在異步回調中有promesses.push(promesse);調用,只有在讀入文件後纔會執行該調用。將承諾放入數組中的想法是正確的,但必須立即執行,以便在調用Promise.all之前發生陣列。
  • 你由於某種原因從代碼中刪除了Promise.all

基本功能應該有這樣的一般模式:

function buildIndex(…) { 
    … 
    var promises = paths.map(function(path) { 
    if (isDir(path)) { 
     return buildIndex(…); 
    } else { 
     return JSDOM.fromFile(…).then(…); 
    } 
    }); 
    return Promise.all(promises).then(…); 
} 
+0

非常感謝你從一個新的JS學習者那裏獲得的時間,它似乎工作得很好。 – DnzzL