2017-06-12 8 views
0

現在、ノードJSとJavascriptを学習中です。私はマンガを読んでダウンロードするアプリケーションを開発しようとしています。致命的なエラー:CALL_AND_RETRY_LAST割り当てに失敗しました - Javacriptヒープメモリ不足

まず、データベースを構築したいと思います。ここで私は問題に遭遇します。 私は4GBのRAM(私のDBを埋めるために)を持って私のサーバー上で私のプログラムを実行すると、メモリから致命的なエラーJavascriptのヒープを取得します。

8GBのRAMを搭載したローカルコンピュータで同じプログラムを実行すると、すべてが正常に動作します。

ここで私は漫画の章で私のDBを埋めるコードです。

function insertChapters(callback){ 

    sql_selectAll("Mangas", function (selectError, selectResult) { 
     if(!selectError){ 
      selectResult.forEach(function (mangaItem, mangaIndex) { 
       gin.mangafox.chapters(mangaItem.Title) 
        .then(chapters =>{ 

         chapters.forEach(function (chapterItem) { 
          var Chapter = { 
           Title: chapterItem.name, 
           NR: chapterItem.chap_number, 
           URL: chapterItem.src, 
           MangaID: mangaItem.MangaID, 
           MangaName: mangaItem.Title, 
           VolumeNR: chapterItem.volume 
          }; 
          sql_insertInto("Chapters", Chapter, function (insertError, insertResult) { 
          if(!insertError){ 
           var insertedChapter = 
           "------------------------------------------------------------------------\n" + 
           " Added new Chapter: " + Chapter.NR + " For: " + mangaItem.Title + "\n" + 
           "------------------------------------------------------------------------\n"; 
           callback(null,insertedChapter ,insertResult); 
          } 
          else{ 
           if(insertError.code === "ER_DUP_ENTRY") { 
            var dupEntry = "------------------------------------------------------------------------\n" + 
                " Duplicate Entry: Chapter: " + Chapter.NR + " For: " + mangaItem.Title + "\n" + 
                "------------------------------------------------------------------------\n" 

             callback(null, dupEntry, null); 
            } 
            else{ 
             callback(insertError, null, null); 
            } 
           } 
          }) 
         }) 

        }) 
        .catch(fetchChapterError => { 
         callback(fetchChapterError, null, null); 
        }) 
      }) 
     } 
     else{ 
      callback(selectError, null, null); 
     } 
    }); 
}` 

私は問題が何であるかイムわからないので、実際に、この問題を解決する方法を知らない:

  1. は、私は自分のサーバーに十分なRAMを持っていけない単にという問題ですか?
  2. 私のコードに問題はありますか?私はどこかに記憶を漏らしていますか?
  3. 私のコードでメモリが大量に必要なことはありますか?

ありがとうございます。私が得ることができるすべてのヘルプに感謝します。

EDIT:

function sql_selectAll(tableName, callback){ 
    var sql = 'SELECT * FROM `' + tableName + '`'; 
    connection.query(sql, function (err, selectAllResult) { 
     callback(err, selectAllResult); 
    }) 
} 

function sql_insertInto(tableName, insertionObject, callback) { 
    var sql = 'insert into ' + tableName + ' set ?'; 
    connection.query(sql, insertionObject, function (err, insertResult) { 
     callback(err, insertResult); 
    }); 
} 
+0

最初のSQLクエリで返される結果の数はいくつですか?また、SQLのすべての結果に対してただちに 'gin.mangafox.chapters'エンドポイントを呼び出して、すべての結果が戻ってくるのを待っていることに注意することが重要です。JSでの非同期プログラミングがどのように機能するのですか?非同期呼び出しが待機している間、コードは実行され続けます。 'forEach'を呼び出すと、コール間で非同期の結果が返ってくるのを待つことなく、すべての項目に対して指定された関数がすぐに実行されます。あなたのDBに何百ものマンガがあるなら、同時に何百ものAPIコールをやっています。 – sbking

+0

初期クエリでは約19.000の結果が返され、これらの19.000の平均値は15-20の章があります。 もっとメモリに優しいアプローチがありますか?私はまだ非同期プログラミングの周りに頭を抱えようとしています。 ありがとうございました。 – calgara12

+0

はい、managafox APIエンドポイント*への19000リクエストを同時に行っています。プログラムは一度に1つずつ、またはチャンクではなく、あまりに多くの非同期要求を追跡しようとしているため、メモリが不足しています。 JSの非同期/待機機能を調べましたか?また、SQL呼び出しには何を使用していますか?私は 'sql_selectAll'や' sql_insertInto'のようなメソッドを認識しません。これらのメソッドが約束を返すならば、async/awaitを使って関数をどのように構造化できるかを示すことができます。 – sbking

答えて

0

あなたは同時に、すべてのSQL結果のためにmangafoxエンドポイントを呼び出すのではなく、一度にまたはチャンクで1されています。これにはasync/awaitを試してみてください。私はあなたが使用しているSQL APIに精通していないんだけど、彼らはコールバックを与えられていない場合、あなたはこのような何かにあなたの関数を書き換えることができますpromises方法sql_selectAllsql_insertIntoリターンと仮定:

async function insertChapters(callback) { 
    try { 
     const mangas = await sql_selectAll("Mangas"); 
     for (const mangaItem of mangas) { 
      const chapters = await gin.mangafox.chapters(mangaItem.Title); 
      for (const chapterItem of chapters) { 
       const Chapter = { 
        Title: chapterItem.name, 
        NR: chapterItem.chap_number, 
        URL: chapterItem.src, 
        MangaID: mangaItem.MangaID, 
        MangaName: mangaItem.Title, 
        VolumeNR: chapterItem.volume 
       }; 
       try { 
        const insertResult = await sql_insertInto("Chapters", Chapter); 
        const insertedChapter = 
        "------------------------------------------------------------------------\n" + 
        " Added new Chapter: " + Chapter.NR + " For: " + mangaItem.Title + "\n" + 
        "------------------------------------------------------------------------\n"; 
        callback(null, insertedChapter, insertResult); 
       } catch (error) { 
        if (error.code === "ER_DUP_ENTRY") { 
         const dupEntry = "------------------------------------------------------------------------\n" + 
             " Duplicate Entry: Chapter: " + Chapter.NR + " For: " + mangaItem.Title + "\n" + 
             "------------------------------------------------------------------------\n"; 
         callback(null, dupEntry, null); 
        } else { 
         throw error; 
        } 
       } 
      } 
     } 
    } catch (error) { 
     callback(error, null, null); 
    } 
} 

お知らせawaitキーワード - これはasync functionで許可されており、JSエンジンにasync関数の実行を一時停止するように指示し、待っている約束が解決されるまで何かを行います。

awaitキーワードを使用して約束事を処理する場合、通常の旧式のtry/catchブロックを使用することもできます。私はfetchChapterErrorを処理するために特別なことをしませんでした。なぜなら、それは最も外側のcatchブロックによって処理されるからです!また、挿入エラーの場合、重複したエントリでなければ、エラーを再スローして、一番外側のキャッチブロックにもキャッチさせることができます。あなたはノード8を使用していない場合は、あなたが(別のpromisifyの実装を使用することができます

const util = require('util'); 
sql_selectAll = util.promisify(sql_selectAll); 

util.promisify

あなたのSQL関数は、ノードのバージョン8で、その後、約束を返さない場合は(最新)を使用できたとえば、bluebirdをチェックしてください)、またはあなた自身で簡単に書くことができます(約束事のMDN記事を読んでください)。

+0

ありがとうございました。私はそれを試してみてください非常に役に立ちました! – calgara12

+0

@ calgara12また、' async function'は自動的に約束を返すので、関数のコールバック引数を取り除く方がはるかに良いでしょう。あるいは 'try {await insertChapters()} catch(error){/*...*/}'を呼び出すために別の非同期関数を使うことができます。しかし、あなたのコードのトップレベルでは、おそらく 'then' /' catch'を一度使う必要があります。非同期関数内でのみ 'await'を使うことができ、その非同期関数が返す約束を処理できるようにしたいからです。 – sbking

関連する問題