javascript - 这两个代码之间有什么区别?

标签 javascript nightmare

我昨天问了一个问题。可以解决,谢谢您的回答。
但是我还有另一个关于堆内存不足的问题。

代码的描述:
这是用于在网站中自动随机回答单词的代码。在第一次循环之前,它们是进入目标网站的代码。在下一个循环之前,这些代码用于移动其他页面。在第二个循环中,它按顺序检查单选按钮。

我最初是写代码的,但是终端发出了一个错误...

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

这是第一个代码。
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();

收到错误后,我对代码进行了一些更改。
第二个代码是这样,
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);

}

主要的();

然后,我又遇到另一个错误,内存不足。
<--- 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

谁能帮我?

最佳答案

实际的问题不在于两个代码之间的差异,而在于如何编写代码以及显示内存问题。

在继续之前,这里有一些链接,请务必阅读它们,否则您将无法理解我在这里所说的内容,从这里了解有关回调,Promise,Promise Chaining,Promise API和Async Await的信息,还有大量其他可用资源,只需选择一个您很了解的。
-https://javascript.info/async

好的,在您完成上述资源的工作并充分了解基础知识之后,我们将继续解决主要问题。

每当您编写此nightmare时,您都将异步调用它。因此,如果您编写nightmare.goto(),它将告诉您 Nightmare 或浏览器实例要访问​​某个网站。并且,如果您编写nightmare.title(),则意味着为您提供网站的标题。

但是,现在它正忙于访问该网站,那么它将如何知道何时完成加载以及何时获得实际标题?

与for循环相同,您看到的是, Nightmare 被调用了43次,但是它不知道它是否应该只是执行您现在要求执行的操作还是应该逐个执行。
因此,当您尝试给它做太多的任务时,会感到困惑,并且不知道先要做哪些工作,然后再做哪些工作。

有异步/等待, promise 和生成器。使用这些技术(现在,让我们说这些只是一些技术),我们可以告诉 Nightmare 一个接一个地运行我们的任务,因此不会感到困惑。

另外,如果看到文档,我们将看到每当您对代码执行.evaluate时,它将返回一些数据,除了获取数据或捕获错误之外,您将无能为力。因此,evaluate().then().evaluate()基本上是导致您的第一个代码错误/损坏的原因。

与其固定第二个代码,不如让我们一个个地固定第一个代码。
首先确保main()是一个异步函数。

async function main() {

在那里,该功能现在是异步的。我们可以在此函数内使用await。我们将通过等待nightmare Promise链来做到这一点。
await nightmare
  .goto(LinguaURL)
  .wait(1000)
  // rest of your code

同样需要等待for循环内的 Nightmare ,
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);

现在进入evaluate问题。我们必须分开evaluate调用。所以,
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

然后将评估移到另一个等待块,
 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;
     }
    });

等我们完成时,可以使用它,
await nightmare
  .wait(100)
  .end()
  .then(console.log);

请注意,我是如何在某些地方添加await的,并且在我的节点8+版本上工作吗?

好的,我看到许多其他错误可能会导致代码失败,例如您在promise函数中返回错误的方式以及许多其他小错误。但是,我希望这可以帮助您解决您的问题。

请记住,如有疑问,请阅读,搜索和询问。

专注于实际问题(即:具有基本的基础知识,编写适当的代码等),而不是您认为的第一个问题(即:两个代码之间的差异)

希望这对您有帮助。和平。

关于javascript - 这两个代码之间有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51596803/

相关文章:

java - 在 jsp 上设置 Ajax 响应不起作用

javascript - 将复杂的 SVG 文件与 paper.js 结合起来

javascript - 在表单提交时获取对 _blank 目标窗口的引用

qa - CodeceptJS和Nightmare-在帮助程序类中的套件之前设置cookie

javascript - React中的JS渲染

javascript - 尝试使用 jQuery 获取当前所选元素的下一个元素的值

javascript - 更改时如何将键作为 v-for 的选择选项值传递(VueJS)

javascript - Nightmarejs-如何读取表行内容?

javascript - 全局设置请求头