Форум программистов, компьютерный форум, киберфорум
Node.js
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.77/13: Рейтинг темы: голосов - 13, средняя оценка - 4.77
 Аватар для kristow
0 / 0 / 2
Регистрация: 27.11.2013
Сообщений: 78

Многозадачность с Nightmare js

14.09.2017, 18:53. Показов 2672. Ответов 2

Студворк — интернет-сервис помощи студентам
Я по примерам написал функцию, в которой Nightmare парсит страницу.
При отладке я запускал функцию с одним параметром, и все работало.

Когда я делаю массив с данными и перебором запускаю функцию парсера, то мне кидает ошибку:
(node:3056) Warning: Possible EventEmitter memory leak detected. 11 close listen
ers added. Use emitter.setMaxListeners() to increase limit


JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
const Nightmare = require('nightmare');
const dream = Nightmare({show: 'true'});
 
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
 
myEmitter.on('error', (err) => {
  console.log('whoops! there was an error');
});
 
myEmitter.on('db_connect', function(){
  dbconn.connect(function(err){
      if(err){
        console.log('Database connection error');
      }else{
        console.log('Database connection successful');
      }
    });
});
 
dbconn.query('SELECT `id`, `operator`, `telefon`, `password`, `data` FROM `base` LIMIT 2', function (error, results, fields) {
    if (error) throw error;
    myEmitter.emit('db_connect');
    for (i = 0; i < results.length; i++) { 
        myEmitter.emit('beeline', results[i].id, results[i].telefon, results[i].password);
    }
});
 
myEmitter.on('beeline', function(base_id, login, pass){
    console.log('<=====RUN balance: '+login+'=====>');
    dream.goto('https://my.beeline.ru')
      .insert('input[name="loginFormB2C:loginForm:login"]', login)
      .insert('input[name="loginFormB2C:loginForm:passwordPwd"]', pass)
      .insert('input[name="loginFormB2C:loginForm:password"]', pass)
      .click('a[onclick="togglePasswordField(this)"]')
      .wait(5000)
      .end()
      .catch((error) => {
        console.error('Search failed:', error);
      });
  
});
при таком коде ошибки нет, но и Nightmare не стартует, хотя лог записи из функции пишутся....
Подскажите как правильно запустить многопоточность в моем случае? Или если Nightmare не работает с многопоточностью, то как без нее по очереди выполнять функции?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
14.09.2017, 18:53
Ответы с готовыми решениями:

как у Nightmare сохранять и использовать куки?
Доброго времени суток. Запускаю Nightmare, и каждый раз авторизация на сайте проходит заново. Как сделать, чтобы после успешной...

Как перемещаться по ссылкам у которых один класс с пакетом nightmare
Есть 30 ссылок на одной странице, как по ним передвигаться?

Многозадачность
Есть программа в которой нажимается кнопка и идет процесс обработки, в то время пока идет процесс обработки кнопка находится в залипнутом...

2
 Аватар для ЛеЖиК)
186 / 61 / 4
Регистрация: 29.04.2011
Сообщений: 641
25.09.2017, 18:28
После обработки первого запроса срабатывает nightmare.end(). Это закрывает твой объект Nightmare. Больше пользоваться им тв не можешь.
1 вариант: не использовать эту строку. Но тогда процесс node не будет сам завершаться. Надо будет обрабатывать событие закрытая процесса и там вызывать Nightmare.end(). Так же возникнет проблема с тем, что у тебя один объект, а действия надо выполнять одновременно.
Получится, что команды к nightmare перемешаются. Может случится следующие:
1.перешел на страницу aaaa.ru
2. Что то нажал
3. Стал ждать результата
4. В этот момент пришёл новый запрос. Перейти по адресу bbbb.ru
5. Перешёл с адреса aaaa.ru на bbbb.ru. Естественно, потерялось то, что ждали в шаге 3. В ответ клиенту вернётся не связанная с ним информация.

Что б ловить такие косяки, рекомендую после каждой строки действия с nightmare, в лог выводить, что сделал.
Сразу станет понятно, чтотоеально происходит.

Поэтому рекомендую вариант 2: для каждого создавать отдельный объект nightmare. Не забывай оператор new.
То есть я предлагаю строку
Const dream=Nightmare.....
помесить в внутрь события beeline, и заменить на
Const dream=new nightmare.....



Не уверен что это совет правильный: каждый созданный объект nightmare, создаёт дочерний процесс electron, что жрет оперативку, процессор и тд.
У меня на сервере начинаются проблемы при 30 одновременных процессах electron. Так что следи за общим количеством. Затормаживай создание новых объектов, когда их станет слишком много.

Я, для ускорения процесса работы, создаю пул объектов при старте сервера. А потом пользуюсь свободными.

Буду рад, если знающие люди подскажут, правильное ли это решение.


Извиняюсь за отсутсвие оформления: пишу с телефона.
0
Coding is art
Эксперт JS
540 / 423 / 154
Регистрация: 04.09.2013
Сообщений: 1,066
26.09.2017, 01:52
1.
Цитата Сообщение от kristow Посмотреть сообщение
(node:3056) Warning: Possible EventEmitter memory leak detected. 11 close listen
ers added. Use emitter.setMaxListeners() to increase limit
Предупреждение уровня EventEmitter, которое гласит, что на событие было подписано событий больше, чем определённое кол-во..
обычно такое происходит когда делается что-то типо
JavaScript
1
2
3
for(let i = 0; i < 20; i++) {
  myEmitter.on('some_event', someFunction.bind(null, i));
}
Присваивается куча функций к одному и тому же событию.
По умолчанию это кол-во = 10, но можно перезаписать воспользовавшись функцией
JavaScript
1
myEmitter..setMaxListeners(20);
2.
Цитата Сообщение от kristow Посмотреть сообщение
if (error) throw error;
* * myEmitter.emit('db_connect');
Не совсем понятна логика происходящего.
Вы открываете соединение после того, как сделали запрос ?? как это работает и зачем ?
JavaScript
1
myEmitter.emit('db_connect');
должен вызываться до того, как вызывать
JavaScript
1
dbconn.query('SELECT `id`, `op....);
При чём dbconn.query должен вызываться в "колбеке" от dbconn.connect (тогда соединение открыто и можно делать запросы).

3.
Как уже подметили в комментарии выше - используя .end() вы закрываете Nightmare, тут у вас есть возможность изменить вот так например:
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
myEmitter.on('beeline', function(base_id, login, pass){
    console.log('<=====RUN balance: '+login+'=====>');
    Nightmare({show: 'true'}).goto('https://my.beeline.ru')
      .insert('input[name="loginFormB2C:loginForm:login"]', login)
      .insert('input[name="loginFormB2C:loginForm:passwordPwd"]', pass)
      .insert('input[name="loginFormB2C:loginForm:password"]', pass)
      .click('a[onclick="togglePasswordField(this)"]')
      .wait(5000)
      .end()
      .catch((error) => {
        console.error('Search failed:', error);
      });
});
Но как сказали выше - это создаст кучу инстансов электрона что заполнит вашу память..

и второй вариант который я вижу:
сделать промис и выполнять его "последовательно" в отдельном экшене,
что-то типо такого:
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
....
for (i = 0; i < results.length; i++) { 
        myEmitter.emit('beeline', results[i].id, results[i].telefon, results[i].password);
    }
myEmitter.emit('execute');
....
let promise = Promise.resolve();
myEmitter.on('beeline', function(base_id, login, pass){
    console.log('<=====RUN balance: '+login+'=====>');
    promise = promise.then(() => {
        return new Promise((resolve, reject) => {
            dream.goto('https://my.beeline.ru')
            .insert('input[name="loginFormB2C:loginForm:login"]', login)
            .insert('input[name="loginFormB2C:loginForm:passwordPwd"]', pass)
            .insert('input[name="loginFormB2C:loginForm:password"]', pass)
            .click('a[onclick="togglePasswordField(this)"]')
            .wait(5000)
            .then(resolve)
            .catch(reject);
        });
    });
});
 
myEmitter.on('execute', function() {
    console.log('Run everything...');
    promise.then(() => {
        console.log('All manipulations are done!');
        dream.end();
    });
});
Получается что мы собираем все выполнения nightmare в один большой промис, где каждое открытие страницы и ввод данных будет выполнятся последовательно. Что понизит время выполнения.

Не очень понятно конечно зачем вы используете EventEmitter, от тут вообще не нужен..
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
26.09.2017, 01:52
Помогаю со студенческими работами здесь

Многозадачность
Здравствуйте!Пишу программу,использующую многозадачность.Возникли вопросы: 1)Строг ли порядок следования дескрипторов в GDT? 2)Нужны ли...

Многозадачность в DOS
Хочу написать что-то типа надстройки на DOS, но как-то неудобно, что там одновременно может выполняться ток одна программа. :( Можно...

Многозадачность RadioButton
Здравствуйте, Подскажите пожалуйста, Как сделать так, что бы я смог поставить несколько галочек в компоненте радиобатон, Пример: ...

Многозадачность в Unix
Написать систему из нескольких независимых процессов, вычисляющих гипотенузу по двум катетам. Процессы должны отображать на экране ход...

Многозадачность в Linux
Есть такая программа: #include&lt;stdio.h&gt; #include&lt;sys/types.h&gt; void main() { pid_t pid=fork(); if(pid==0)...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
3
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru