2016-11-29 5 views
0

Я пишу приложение node.js, которое позволяет пользователю создавать многостраничные pdf-файлы в node.js.Выполнение нескольких фантомных процессов для множественных запросов асинхронных в Node.js

Я создаю страницы один за другим и передаю отдельные страницы в виде массива с запросом функции для работы до тех пор, пока все страницы не будут созданы, и в это время я использую PDF-слияние для объединения многостраничного документа.

function pdfExport_map(site, siteData, req){ 
    phantom.pdf_export_map(site, siteData, req, pdfExport_census); 
} 

function pdfExport_census(site, siteData, req){ 
    phantom.pdf_export_census(site, siteData, req, pdfExport_ue); 
} 

function pdfExport_ue(site, siteData, req){ 
    phantom.pdf_export_ue(site, siteData, req, pdfExport_decay); 
} 

function pdfExport_decay(site, siteData, req){ 
    phantom.pdf_export_decay(site, siteData, req, processSites); 
} 

function processSites(req) { 
     var pdfMerge = new PDFMerge(req.fileStack, 'C:\\Program Files (x86)\\PDFtk\\bin\\pdftk.exe'); 
     var d = Date.now(); 
     var filename = 'r' + d.toString() + '.pdf'; 
     pdfMerge.asNewFile(process.env.FILEPATH + filename).merge(function (error, file) { 
      console.log(file); 
     }); 
} 

Это работает достаточно хорошо, если один пользователь запускает процесс. Если несколько пользователей запускают процесс одновременно, только один пользователь получает отчет. Процесс терпит неудачу с фантомными обещаниями. Когда я устанавливаю точки останова в следующей функции, я вижу, что данные для сайта B получены (точка останова 1) до того, как сайт A был экспортирован как PDF (точка останова 2). На этом этапе процесс для сайта B никогда не заберет.

function pdf_export_map(site, siteData, req, _pdfExport_census) { 
    phantom.create() 
     .then(instance => { 
      ph = instance; 
      return instance.createPage(); 
     }) 
     .then(p => { 
      page = p; 
      page.open('about:blank'); 
     }) 
     .then(function() { 
      var renderTimeout, 
       c = 0; 

      function doRender() { 
       console.log('page loaded'); 
       var d = Date.now(); 
       var filename = 'm' + d.toString() + '.pdf'; 
       page.render('tmp/' + filename) 
        .then(function() { 


//breakpoint 2 page PDF export complete 
         ph.exit(); 
         req.fileStack.push(process.env.FILEPATH + filename); 
         _pdfExport_census(site, siteData, req) 
        }); 
      } 

      page.on('onResourceRequested', function (r) { 
       c++; 
       console.log(('000' + r.id).slice(-4) + ' | ' + r.url); 
       clearTimeout(renderTimeout); 
      }); 

      page.on('onResourceReceived', function (r) { 
       if (!r.stage || r.stage === 'end') { 
        c--; 
        console.log(('000' + r.id).slice(-4) + ' | ' + r.status); 
        if (c === 0) { 
         renderTimeout = setTimeout(doRender, 5000); 
        } 
       } 
      }); 

      if (process.platform == 'win32') { 
       page.property('paperSize', { 
        width: '11in', 
        height: '8.5in' 
       }); 
      } else { 
       page.property('paperSize', { 
        width: '1056px', 
        height: '816px' 
       }); 
      } 

      page.property('viewportSize', { 
       width: 1056, 
       height: 816 
      }); 

      page.property('clipRect', { 
       top: 0, 
       left: 0, 
       width: 1056, 
       height: 816 
      }); 


//breakpoint 1 data received, start render 
      ejs.renderFile('views/phantommap.ejs', { 
       site: site, 
       features: siteData.features, 
       subdirectory: process.env.SUBDIRECTORY, 
       page: req.fileStack.length + 1 
      }, function (err, html) { 
       page.setContent(html, 'http://' + process.env.HOST + '/amazon/phantommap'); 
      }); 

     }) 
     .catch(err => { 
      console.log(err); 
      ph.exit(); 
     }); 
} 

У меня плохое представление о фантоме и обещаниях. Можно ли запустить этот синхронный, например, завершите страницу для одного сайта, а затем запустите страницу для второго отчета?

Редактировать: Выполнение нескольких тестов Я прокомментировал ph.exit(). Я вижу, что я получаю данные для сайта A и для сайта B. Но страница для сайта A экспортируется дважды.

Редактировать: После рекомендации Амира я получил эту работу, объявив ph и страницу внутри функции так.

phantom.create() 
    .then(instance => { 
     _ph = instance; 
     return instance.createPage(); 
    }) 
    .then(p => { 
     _page = p; 
     _page.open('about:blank'); 
    }) 
    .then(function() { 
     var renderTimeout, 
      c = 0, 
      ph = _ph, 
      page = _page; 

Мне все еще нужно изучить использование async и ждать.

ответ

2

Я подозреваю, что ваш код не является потокобезопасным. Я вижу, что у вас есть переменная, называемая ph. Является ли это глобальным var, который используется для разных запросов? Если это так, есть ваша проблема. Вы обмениваетесь экземплярами. Вместо этого вы не должны использовать глобальные переменные и закрывать фантомный экземпляр только для этого запроса.

Аналогичная проблема была представлена ​​на фантоме по адресу https://github.com/amir20/phantomjs-node/issues/583. Но проблема заключалась в том, что он повторно использовал экземпляр фантомного процесса.

Несколько рекомендаций для вашего кода. Вместо этого используйте async и await. Этот обратный ад приведет вас с ума сойти. Не используйте глобальные переменные, объявленные за пределами вашего сеанса для каждого запроса. Обмен данными между запросами будет иметь неожиданные результаты.

Отказ от ответственности: Я являюсь автором PhantomJs-Node.

+2

Еще раз спасибо за помощь. Модуль phantomjs является удивительным. Посмотрите на использование async и ждите. Приветствия. –

+1

Вы, безусловно, приветствуетесь и благодарны за принятие моего ответа. –

+0

У меня есть вопрос относительно этой проблемы. Это означает, что мы не можем повторно использовать процесс phantomjs.exe для нескольких запросов? Проблема с phantomjs.exe заключается в том, что процесс запуска занимает до 7 секунд, и запросы выполняются быстро. Но если у вас есть 40 запросов на выполнение, вы можете рассчитать, сколько времени это, по крайней мере, займет ... слишком много. – Legends

Смежные вопросы