N
N
ndbn2016-10-13 13:54:20
Node.js
ndbn, 2016-10-13 13:54:20

How to implement a script structure with asynchronous requests?

The question is not new, but I do not understand how to organize the script for normal operation. The problem, of course, is in asynchronous requests.
The task is simple - to parse data from the site (REST API);
I imagine like this (pseudo-pseudo-code):

//  функция_получить_число_записей  - уже должна выполнить запрос, чтобы получить число записей. 
// Запрос асинхронный.
var cnt = функция_получить_число_записей();

for(каждая запись)
{
  //функция_получить_запись - запрос данных с сайта. Запрос асинхронный.
   var данные = функция_получить_данные(запись);
    функция_обработать_данные(данные);
}

var request = require('request-json');
var Q = require('q');

var client = request.createClient(SITE_URL);

// Обертка для асинхнонной функции
// (https://strongloop.com/strongblog/promises-in-node-js-with-q-an-alternative-to-callbacks/)
function client_post(path, data, callback) {
    var deferred = Q.defer();

    client.post(path, data, function (err, res, body) {
        if (err)
            deferred.reject(err); // rejects the promise with `er` as the reason
        else
            deferred.resolve(body); // fulfills the promise with `data` as the value
    });

    return deferred.promise.nodeify(callback); // the promise is returned
}


//Отправляет запрос на сайт
function requestData(data)
{    client_post(SITE_PATH, data, function (err, res) {
        return res;
    });
}

//Создает JSON объект с параметрами запроса
function createDataStruct(pageNumber){ ... }

var data = createDataStruct(61, 1, 1);
var res = requestData(data);

I spied on one site how to create a promise - a version of an asynchronous function (client_post), but this does absolutely nothing, instead of using callback 'ka of the function itself, we use a callback that is passed as a parameter. In general, I don’t understand, tell me what to see, read, what approach to use.
Thank you!

Answer the question

In order to leave comments, you need to log in

2 answer(s)
K
Kirill, 2016-10-13
@ndbn

You can use the magic of ES6 and bluebirdjs:

const request = require('request-json');
const Promise = require('bluebird');

let client = request.createClient(SITE_URL);

client.post = Promise.promisify(client.post);

Promise.coroutine(function* () {
    let data1 = createDataStruct(61, 1, 1);
    let result1 = yield client.post(SITE_PATH, data);

    let data2 = createDataStruct(61, 1, 1);
    let result2 = yield client.post(SITE_PATH, data);

    console.log(result1, result2);
})();

I did not check whether it will work, but I strongly advise you to look in the direction of coroutines, generators, and especially in the direction of bluebird.

D
de1m, 2016-10-13
@de1m

Something similar was needed recently. For example - I have an array with servers and on each server I have several folders that I need to check.

self.startVerifyBackup(listOfServer).then(function (outArr) {
        return callback(null, outArr);
      }).catch(function (err) {
        return callback(err, null);
      });

Here I am passing an array from the servers.
Here is the function itself
verifyBackup.prototype.startVerifyBackup = function (folderList) {
  var self = this;

  return Promise.all(folderList.map(function (folder) {
    return self.checkFolder(folder);
  }));
};

And a function that checks all folders on each server
verifyBackup.prototype.checkFolder = function (folder) {
  var self = this;
  return new Promise(function (resolve, reject) {
    if (self.config.backupserver[self.bserver].passphrase !== undefined && self.config.backupserver[self.bserver].passphrase !== null) {
      var passphrase = "PASSPHRASE=" + self.config.backupserver[self.bserver].passphrase;
    } else {
      var passphrase = "";
    }
    if (self.config.backupserver[self.bserver].tmpdir !== undefined && self.config.backupserver[self.bserver].tmpdir !== null) {
      var btemp = self.config.backupserver[self.bserver].tmpdir;
    } else {
      var btemp = "";
    }

    var command = "sudo " + passphrase + " duplicity verify file://" + folder + " " + btemp;
    self.runSSH(command, self.sshkeypath, self.eserver, self.bserver, function (err, data) {
      if (err) {
        return reject(err);
      } else {

        var output = data.toString().split("\n");
        output.splice(0, 2);
        var objReturn = {
          name: folder,
          output: output
        };
        return resolve(objReturn);
      }
    });
  });
};

This is how it should look like, although I think that my errors are a little not correctly processed.
You can also use the async library instead of promis. But adherents of promis'ov are against, although there are more opportunities.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question