0

trying implement this function:

   module.exports.top = function (n) {
        request(getOptions(reposURL), callback);
        //use result[]
    };

result is array, that I got in Promise.all:

function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        var repos = JSON.parse(body);
        var promises = [];
        repos.forEach(function (repo) {
            if (condition...) {
                //adding promises to promises[]
            }
        });
        Promise.all(promises).then(res => {
            var result = getResult(anotherFunction(res));
            //return result to top function
        });
    }
};

can't understand how to return result to top function and use it only when request and functions in Promise.all are completed. how can i do it?

2 Answers2

3

(Note: I've used ES2015 throughout, since your question included an arrow function. If you need to use it in an ES5 environment and aren't transpiling, you can get a transpiled result using Babel's REPL.)

Step 1 is to make callback return a promise:

function callback(error, response, body) {
    if (error || response.statusCode != 200) {
        // Adjust the rejection as necessary...
        return Promise.reject({error, statusCode: response.statusCode});
    }

    let repos = JSON.parse(body);
    let promises = [];
    repos.forEach(repo => {
        if (condition...) {
            //adding promises to promises[]
        }
    });
    return Promise.all(promises).then(res => getResult(anotherFunction(res)));
}

Then how you use that in request depends on what request returns, but given it accepts a callback, I'm going to assume here that it doesn't return anything (as opposed to returning a promise, which would have been useful). If that assumption is correct, we need to create a new promise, and have that promise wait for callback's promise:

module.exports.top = function (n) {
    let p = new Promise((resolve, reject) => {
        request(getOptions(reposURL), () => {
            callback.apply(this, arguments)
                .then(resolve)
                .catch(reject);
        });
    });
    return p;
};

Now, top returns a promise that will be fulfilled by the result of Promise.all in callback.


Of course, if request is a function you can change, we can promise-ify the entire chain, which would be a lot cleaner:

function request(arg) {
    return new Promise((resolve, reject) => {
        // ...do the work, call resolve or reject as appropriate
    });
}

callback is largely the same, but doesn't have to handle the error arguments anymore:

function callback(body) {
    let repos = JSON.parse(body);
    let promises = [];
    repos.forEach(repo => {
        if (condition...) {
            //adding promises to promises[]
        }
    });
    return Promise.all(promises).then(res => getResult(anotherFunction(res)));
}

and then top is quite simple:

module.exports.top = function (n) {
    return request(getOptions(reposURL))
        .then(callback);
};

This is the great thing about promises, they're composible.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
0

return your Promise in the callback function. Also return the callback in your request function. Then you can use the the function as a chained promise like this:

module.exports.top = function (n) {
    request(getOptions(reposURL), callback).then(result => {
        //use result[]
    });
}

function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        var repos = JSON.parse(body);
        var promises = [];
        repos.forEach(function (repo) {
            if (condition...) {
                //adding promises to promises[]
            }
        });
        return Promise.all(promises).then(res => {
            var result = getResult(anotherFunction(res));
            //return result to top function
            return result;
        });
    }
};
  • Given that `request` is quite clearly asynchronous, *"`return` the `callback` in your `request` function"* makes no sense. Also, you might want to handle the rejection case... *And* make the information available from `top`. – T.J. Crowder Feb 21 '16 at 10:42