Взяв простейший пример, скажем, что это два или более парней, которым необходимо отправить данные с помощью HTTP-запроса, данные, представленные одним из парней, должны ждать, пока другие данные будут отправлены другими парнями на сервер в чтобы быть разобранным Вот изображение того, чего я пытаюсь достичь в Node.js:

enter image description here

Когда данные анализируются, они должны быть отправлены обратно как ответы каждому из парней. Проблема в том, что я застрял при реализации этой задачи (я использую модуль http, и длинный опрос, позже я буду использовать websocket), проблема заключается в природе обратных вызовов, и я попытался использовать грязные методы, такие как создание массива, который является заполняется до тех пор, пока все не отправят, и проверяет с помощью функции setInterval, где пора разбирать данные и так далее.

Есть ли более чистые и менее грязные способы реализации таких задач?

1
DomainFlag 27 Авг 2017 в 14:55

3 ответа

Лучший ответ

Я бы дал уникальный идентификатор этому процессу (который знают оба клиента), а затем сохранил соответствующие данные в базе данных или непосредственно в оперативной памяти сервера. Наличие ожидающих запросов (запрос - ожидание) плохо для сервера, поскольку он должен поддерживать все больше открытых соединений, и плохо для клиента, так как он видит вращающийся круг, не зная, что происходит. Я бы предпочел сделать следующее:

1. client sends request with data
      2. data gets stored, a *please wait* is returned
3. the page reloads all two seconds
      4. if all the datas there, return the data
      5. if not, return *please wait* and goto 3

Псевдоимплементация будет выглядеть так:

var processes = new Map();

function Process (){
  do {
   var id = Math floor(Math.random()*10**10);
  }while(processes.has(id));
  this.id = id;
  processes.set(id,this);
}

Process.prototype.pending = function(res){
 if(this.first && this.second) 
   return res.end(this.first + this.second);

 res.end(`
  <html>
   <body>
    Please wait... 
    <script> setTimeout(location.reload.bind(location),2000);
    </script>
   </body>
 </html>`);
};

//the routing
var app = Express();

app.get("/create",function(req,res){
 var p = new Process();
 req.end(p.id);
});

app.get("/first/:id/:data",function(req,res){
 var p = processes.get(req.params.id);
 if(!p) return res.end("id not found");
 p.first = req.params.data;
 p.pending(res);
});

app.get("/second/:id/:data",function(req,res){
 var p = processes.get(req.params.id);
 if(!p) return res.end("id not found");
 p.second = req.params.data;
 p.pending(res);
});
2
Jonas Wilms 27 Авг 2017 в 13:41

Как я уже упоминал в своем комментарии, promise.all() в порядке, но вы не можете контролировать выполнение обещаний, как только одно из них будет отклонено.

Вместо этого вы можете связать свои обещания с .reduce(), и у вас будет гораздо больший контроль над разрешенными и отклоненными обещаниями.

var pr1 = new Promise((v,x) => setTimeout(_ => Math.random() > 0.2 ? v("promise 1 resolved value") : x("Promise 1 rejected"),150)),
    pr2 = new Promise((v,x) => setTimeout(_ => Math.random() > 0.2 ? v("promise 2 resolved value") : x("Promise 2 rejected"),120)),
    pr3 = new Promise((v,x) => setTimeout(_ => Math.random() > 0.2 ? v("promise 3 resolved value") : x("Promise 3 rejected"),60)),
    pr4 = new Promise((v,x) => setTimeout(_ => Math.random() > 0.2 ? v("promise 4 resolved value") : x("Promise 4 rejected"),220)),
    pr5 = new Promise((v,x) => setTimeout(_ => Math.random() > 0.2 ? v("promise 5 resolved value") : x("Promise 5 rejected"),180));

[pr1,pr2,pr3,pr4,pr5].reduce((p,c) => p.then(v => (console.log(`doing something with ${v} and will proceed with the next`),c),
                                             x => (console.log(`Error ${x} however i will proceed with the next`),c)))
                     .then(v => console.log(`finally doing something with ${v}`),
                           x => console.log(`Error ${x} received`));
0
Redu 27 Авг 2017 в 12:28

На данный момент самый простой способ - использовать Promise.all

function firstAsyncRequest() {
  return new Promise((resolve, reject) => {
    // do your async call and then resolve();
    // or reject() if any error;
  });
}


function secondAsyncRequest() {
  return new Promise((resolve, reject) => {
    // do your async call and then resolve();
    // or reject() if any error;
  });
}

Promise.all([firstAsyncRequest, secondAsyncRequest])
  .then(arrayOfResults => {
      //do your logic
  })
  .catch(err => {
      //catch your error
  })

Если вместо этого вы используете обратные вызовы, самый простой способ - использовать async модуль, а затем {{X1 } }

async.parallel([
    function(callback) {
        setTimeout(function() {
            callback(null, 'one');
        }, 200);
    },
    function(callback) {
        setTimeout(function() {
            callback(null, 'two');
        }, 100);
    }
],
// optional callback
function(err, results) {
    // the results array will equal ['one','two'] even though
    // the second function had a shorter timeout.
});
1
Alexandru Olaru 27 Авг 2017 в 12:01