-3

I have asked a question yesterday. It could be solved thanks for an answer. But I got another problem about heap out of memory.

Description of the code: this is a code for answering words automatically and randomly in a website. Until first for loop, they are codes for going to a website which is a target. Until next loop, the codes are for moving other pages. And in the second loop, it checks radio button in order.

I wrote the code at first, but terminal issued an error of...

/Users/Papillon/Documents/lingua3.js:60
                .evaluate(function (){
                 ^

TypeError: nightmare.wait(...).click(...).wait(...).click(...).wait(...).evaluate(...).then(...).evaluate is not a function
    at main (/Users/Papillon/Documents/lingua3.js:60:18)
    at Object.<anonymous> (/Users/Papillon/Documents/lingua3.js:91:1)
    at Module._compile (internal/modules/cjs/loader.js:689:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:742:12)
    at startup (internal/bootstrap/node.js:266:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:596:3)

This is the first code.

const Nightmare = require('nightmare');
const nightmare = Nightmare({show: true});

const LinguaURL = "";
const NumberOfMine = "";
const PwdOfMine = "";

var k,i,j = -1;
var randSelection = Math.floor(Math.random()*5);
var radioSelect = 0;
var selection,progress;

function main() {
  nightmare
    .goto(LinguaURL)
    .wait(1000)
    .type("input[type='text']", NumberOfMine)
    .type("input[type='password']", PwdOfMine)
    .click("input[type='submit']")
    .wait(5000)
    .click('a[href="javascript:document.Study.submit()"]')
    .wait(3000)
    .click("input[type='button']")
    .wait(3000);

    for(i = 3;i<43;i++){

      nightmare
        .click('a[OnClick="unit_view_page(\''+i.toString()+'\');"]')
        .wait(1000);
        for(k = 0; k < 10 * 42;k++){
          j++;

          if(j % 4 == 0){
          nightmare
            .click('input[onclick="select_unit(\'drill\', \''+(1833+j).toString()+'\', \'\');"]')
            .wait(500);

            while(true){

              if(radioSelect == 5)radioSelect = 0;

              nightmare
                .wait(2000)
                .click('input[id="answer_0_' + radioSelect.toString() +'"]')
                .wait(1000)
                .click('input[id="ans_submit"]')
                .wait(1000)
                .evaluate(function (){
                  selection = document.querySelector('.btn btn-answer-view form-font-size');
                  progress = document.querySelector('btn btn-next-problem form-font-size');

                  return (selection != null && progress != null);
                })
                .then((result) => {
                  if(result){
                    return false;
                  }
                })
                .evaluate(function (){
                  selection = document.querySelector('.btn btn-answer-view form-font-size');
                  return selection;
                })
                .then((result) => {

                  radioSelect++;

                  if(selection != null){
                    return true;
                  }else{
                    nightmare
                      .click('input[class="btn btn-next-problem form-font-size"]')
                      .wait(1000);
                    radioSelect = 0;
                    return true;
                  }
                });
          }
          if((k + 1) % 10 == 0){
            break;
          }
          }
        }
      }
      nightmare
        .wait(100)
        .end()
        .then(console.log);
}

main();

After getting an error, I changed the code a little. The second code is this,

const Nightmare = require('nightmare');
const nightmare = Nightmare({show: true});

const LinguaURL = "";    //site url
const NumberOfMine = ""; //my id
const PwdOfMine = "";    //my password

var k,i,j = -1;
var randSelection = Math.floor(Math.random()*5);
var radioSelect = 0;
var selection,progress;

function main() {
  nightmare
    .goto(LinguaURL)
    .wait(1000)
    .type("input[type='text']", NumberOfMine)
    .type("input[type='password']", PwdOfMine)
    .click("input[type='submit']")
    .wait(5000)
    .click('a[href="javascript:document.Study.submit()"]')
    .wait(3000)
    .click("input[type='button']")
    .wait(3000);

for(i = 3;i<43;i++){

  nightmare
    .click('a[OnClick="unit_view_page(\''+i.toString()+'\');"]')
    .wait(1000);
    for(k = 0; k < 10 * 42;k++){
      j++;

      if(j % 4 == 0){
      nightmare
        .click('input[onclick="select_unit(\'drill\', \''+(1833+j).toString()+'\', \'\');"]')
        .wait(500);

        while(true){

          if(radioSelect == 5)radioSelect = 0;

          nightmare
            .wait(2000)
            .click('input[id="answer_0_' + radioSelect.toString() +'"]')
            .wait(1000)
            .click('input[id="ans_submit"]')
            .wait(1000)
            .evaluate(function (){
              selection = document.querySelector('.btn btn-answer-view form-font-size');
              progress = document.querySelector('btn btn-next-problem form-font-size');

              return (selection != null && progress != null);
            })
            .then((result) => {
              if(result){
                return false; //means break
              }
            });

          nightmare  //difference of the codes
            .evaluate(function (){
              selection = document.querySelector('.btn btn-answer-view form-font-size');
              return (selection != null);
            })
            .then((result) => {

              radioSelect++;

              if(result){
                return true;
              }else{
                nightmare
                  .click('input[class="btn btn-next-problem form-font-size"]')
                  .wait(1000);
                radioSelect = 0;
                return true;
              }
            });
      }
      if((k + 1) % 10 == 0){
        break;
      }
      }
    }
  }
  nightmare
    .wait(100)
    .end()
    .then(console.log);

}

main();

Then, I got another error, heap out of memory.

<--- Last few GCs --->

[3302:0x102803200]    44201 ms: Scavenge 1389.7 (1424.3) -> 1389.3 (1425.3) MB, 9.4 / 0.0 ms  (average mu = 0.090, current mu = 0.035) allocation failure 
[3302:0x102803200]    48726 ms: Mark-sweep 1390.0 (1425.3) -> 1389.5 (1425.3) MB, 4519.3 / 2.5 ms  (average mu = 0.044, current mu = 0.004) allocation failure scavenge might not succeed


<--- JS stacktrace --->

==== JS stack trace =========================================

    0: ExitFrame [pc: 0x1f7919cc1841]
Security context: 0x2e9fd2b1e6c9 <JSObject>
    1: _send [0x2e9ff5855129] [internal/child_process.js:~636] [pc=0x1f7919cc1cc1](this=0x2e9f3a49c331 <ChildProcess map = 0x2e9f35263999>,message=0x2e9fce5c2fa9 <JSArray[4]>,handle=0x2e9f356822e1 <undefined>,options=0x2e9fce5c3089 <Object map = 0x2e9f35264759>,callback=0x2e9f356822e1 <undefined>)
    2: emit [0x2e9ff585df21] [/Users/Papillon/Documents/node_...

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
 1: 0x1000389cc node::Abort() [/Users/Papillon/.nodebrew/current/bin/node]
 2: 0x100038ba8 node::FatalTryCatch::~FatalTryCatch() [/Users/Papillon/.nodebrew/current/bin/node]
 3: 0x1001a9d5a v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/Users/Papillon/.nodebrew/current/bin/node]
 4: 0x100578772 v8::internal::Heap::FatalProcessOutOfMemory(char const*) [/Users/Papillon/.nodebrew/current/bin/node]
 5: 0x100577729 v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [/Users/Papillon/.nodebrew/current/bin/node]
 6: 0x1005753b8 v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/Users/Papillon/.nodebrew/current/bin/node]
 7: 0x1005818fc v8::internal::Heap::AllocateRawWithRetry(int, v8::internal::AllocationSpace, v8::internal::AllocationAlignment) [/Users/Papillon/.nodebrew/current/bin/node]
 8: 0x10055266a v8::internal::Factory::NewRawOneByteString(int, v8::internal::PretenureFlag) [/Users/Papillon/.nodebrew/current/bin/node]
 9: 0x10067a8f7 v8::internal::String::SlowFlatten(v8::internal::Handle<v8::internal::ConsString>, v8::internal::PretenureFlag) [/Users/Papillon/.nodebrew/current/bin/node]
10: 0x1001c82d5 v8::String::WriteUtf8(char*, int, int*, int) const [/Users/Papillon/.nodebrew/current/bin/node]
11: 0x1000bd5cb node::StringBytes::Write(v8::Isolate*, char*, unsigned long, v8::Local<v8::Value>, node::encoding, int*) [/Users/Papillon/.nodebrew/current/bin/node]
12: 0x1000c1dee int node::StreamBase::WriteString<(node::encoding)1>(v8::FunctionCallbackInfo<v8::Value> const&) [/Users/Papillon/.nodebrew/current/bin/node]
13: 0x1000c62c2 void node::StreamBase::JSMethod<node::LibuvStreamWrap, &(int node::StreamBase::WriteString<(node::encoding)1>(v8::FunctionCallbackInfo<v8::Value> const&))>(v8::FunctionCallbackInfo<v8::Value> const&) [/Users/Papillon/.nodebrew/current/bin/node]
14: 0x1f7919cc1841 
15: 0x1f7919cc1cc1 
Abort trap: 6

Can anyone help me?

Mimin
  • 17
  • 6
  • 3
    Both are a nightmare. – Jonas Wilms Jul 30 '18 at 15:04
  • No difference is there? – Mimin Jul 30 '18 at 15:06
  • You are running asynchronous codes in synchronous ways, make sure to learn about vo, yield and await, etc terms. This can be written as answer, but I am asking you to figure it out first. – Md. Abu Taher Jul 31 '18 at 11:21
  • @Md.AbuTaher Let's see... To be honest, I'm not sure why I should use vo, and what can I figure out? – Mimin Jul 31 '18 at 12:09
  • I'm sorry, I am not sure how to use stack overflow well yet :( – Mimin Jul 31 '18 at 12:11
  • And is this an asynchronous codes? I referred several websites to make it. – Mimin Jul 31 '18 at 12:29
  • Its a big piece of code to explain it in one go. Lots of fundamentals are needed, like how you are looping thru and trying to run many nightmare instances, async-sync and so on. You should try to solve it piece by piece rather than the whole code. – Md. Abu Taher Jul 31 '18 at 14:59

1 Answers1

0

The actual problem is not in the difference between two codes, rather how it is written and showing memory problems.

Before I continue, here are some links, make sure to read them, otherwise you will not understand what I will say here, Learn about Callbacks, Promise, Promises Chaining, Promise API and Async Await from here, there are tons of other resources available, just pick one that you understand well. - https://javascript.info/async

Okay, after you are done with the above resources and know the basics well, we will be continuing the main problem.

Whenever you are writing this nightmare, you are calling it asynchronously. So if you write nightmare.goto() it will tell that nightmare or browser instance to go to some website. And if you write nightmare.title(), it will mean to give you the title of the website.

However right now it's busy going to the website, so how will it know when to finish load and when to get the actual title?

Same with the for loop, you see, you are calling nightmare for 43 times, however it doesn't know if it should just do whatever you asked it to do right now or one by one. So when you are trying to give it too many tasks to do, it will be confused, and won't know which work to do first, which work to do after that.

There comes the async/await, promises and generators. Using those techniques(for now, let's say those are just some techniques), we can tell nightmare to run our tasks one by one, so it won't get confused.

Also, If we see the documentation, we see whenever you do .evaluate on the code, it will return some data, you cannot do anything other than getting the data or or catching the error. So, evaluate().then().evaluate() is basically what made your first code wrong/broken.

Instead of fixing the second code, let us fix the first code one by one. First make sure main() is an async function.

async function main() {

There, the function is async now. We can use await inside this function. We will do so by awaiting the nightmare promise chain.

await nightmare
  .goto(LinguaURL)
  .wait(1000)
  // rest of your code

The nightmare inside the for loop needs to be awaited as well,

await nightmare
  .click('a[OnClick="unit_view_page(\'' + i.toString() + '\');"]')
  .wait(1000);

// rest of the code
await nightmare
 .click('input[onclick="select_unit(\'drill\', \'' + (1833 + j).toString() + '\', \'\');"]')
 .wait(500);

Now onto the evaluate problem. We have to seperate the evaluate calls. So,

await nightmare
  .wait(2000)
  .click('input[id="answer_0_' + radioSelect.toString() + '"]')
  .wait(1000)
  .click('input[id="ans_submit"]')
  .wait(1000)
  .evaluate(function() {
   selection = document.querySelector('.btn btn-answer-view form-font-size');
   progress = document.querySelector('btn btn-next-problem form-font-size');
   return (selection != null && progress != null);
  })
  .then((result) => {
   if (result) {
    return false;
   }
  })
  // we cut the code here

then we move the evaluate to another await block,

 await nightmare
    .evaluate(function() {
     selection = document.querySelector('.btn btn-answer-view form-font-size');
     return selection;
    })
    .then((result) => {

     radioSelect++;

     if (selection != null) {
      return true;
     } else {
      await nightmare // whenever we call something like this, we await it
       .click('input[class="btn btn-next-problem form-font-size"]')
       .wait(1000);
      radioSelect = 0;
      return true;
     }
    });

When we wait to finish, we can use this,

await nightmare
  .wait(100)
  .end()
  .then(console.log);

Notice how I just added await on some places, and it is working on my node 8+ versions?

Okay, I see lots of other errors places where the code might fail, such as you are returning wrong way inside promise functions and lots of other small errors. However, I hope this helps you move through your problem a bit.

Remember, whenever in doubt, Read, Search and Ask.

Focus on the actual problem (ie: having basics about fundamentals, writing proper code etc), instead of first problem you think (ie: difference between two codes)

Hope this finds you well. Peace.

Md. Abu Taher
  • 17,395
  • 5
  • 49
  • 73