简体   繁体   English

使用Promise.all()进行多个http / oauth查询

[英]Using Promise.all() for multiple http/oauth queries

I'm trying to wait for the output of two OAuth calls to an API, and I'm having trouble retrieving the data from those calls. 我正在尝试等待对API的两个OAuth调用的输出,并且在从这些调用中检索数据时遇到了麻烦。 If I use Promise.all(call1,call2).then() I am getting information about the request object. 如果我使用Promise.all(call1,call2).then(),我将获得有关请求对象的信息。

First, here's the setup for the fitbit_oauth object: 首先,这是fitbit_oauth对象的设置:

var fitbit_oauth = new OAuth.OAuth(
    'https://api.fitbit.com/oauth/request_token',
    'https://api.fitbit.com/oauth/access_token',
    config.fitbitClientKey,
    config.fitbitClientSecret,
    '1.0',
    null,
    'HMAC-SHA1'
);

foodpath = 'https://api.fitbit.com/1/user/-/foods/log/date/' + moment().utc().add('ms', user.timezoneOffset).format('YYYY-MM-DD') + '.json';
activitypath = 'https://api.fitbit.com/1/user/-/activities/date/' + moment().utc().add('ms', user.timezoneOffset).format('YYYY-MM-DD') + '.json';

Promise.all([fitbit_oauth.get(foodpath, user.accessToken, user.accessSecret), 
             fitbit_oauth.get(activitypath, user.accessToken,   
                                            user.accessSecret)])
                .then(function(arrayOfResults) {
                    console.log(arrayOfResults);
                }

I want arrayOfResults to give me the data from the calls, not information about the requests. 我希望arrayOfResults给我来自调用的数据,而不是有关请求的信息。 What am I doing wrong here? 我在这里做错了什么? I'm new to promises so I'm sure this is easy for someone who isn't. 我是诺言的新手,所以我确信这对不熟悉的人来说很容易。

The callback for a single fitbit_oauth call is as follows: 单个fitbit_oauth调用的回调如下:

fitbit_oauth.get(
                'https://api.fitbit.com/1/user/-/activities/date/' + moment().utc().add('ms', user.timezoneOffset).format('YYYY-MM-DD') + '.json',
                user.accessToken,
                user.accessSecret,
                function (err, data, res) {
                    if (err) {
                        console.error("Error fetching activity data. ", err);
                        callback(err);
                        return;
                    }

                data = JSON.parse(data);
                console.log("Fitbit Get Activities", data);

                // Update (and return) the user
                User.findOneAndUpdate(
                    {
                        encodedId: user.encodedId
                    },
                    {
                        stepsToday: data.summary.steps,
                        stepsGoal: data.goals.steps
                    },
                    null,
                    function(err, user) {
                        if (err) {
                            console.error("Error updating user activity.", err);
                        }
                        callback(err, user);
                    }
                );
            }
        );

Thanks to jfriend00 I got this working, here's the new code: 多亏了jfriend00,我才能完成这项工作,下面是新代码:

function fitbit_oauth_getP(path, accessToken, accessSecret) {
    return new Promise (function(resolve, reject) {
        fitbit_oauth.get(path, accessToken, accessSecret, function(err, data, res) {
            if (err) {
                 reject(err);
            } else {
                 resolve(data);
            }
        }
     )
})};

Promise.all([fitbit_oauth_getP(foodpath, user.accessToken, user.accessSecret), 
    fitbit_oauth_getP(activitypath, user.accessToken, user.accessSecret)])
        .then(function(arrayOfResults) {
            console.log(arrayOfResults);
    });

Promise.all() only works properly with asynchronous functions when those functions return a promise and when the result of that async operation becomes the resolved (or rejected) value of the promise. Promise.all()仅在异步函数的返回promise且异步操作的结果成为promise的已解决(或拒绝)值时才可以正确使用。

There is no magic in Promise.all() that could somehow know when the fitbit functions are done if they don't return a promise. Promise.all()中没有魔术可以以某种方式知道fitbit函数何时完成(如果它们不返回promise)。

You can still use Promise.all() , but you need to "promisify" the fitbit functions which is a small wrapper around them that turns their normal callback approach into returning a promise that was then resolved or rejected based on the callback result. 您仍然可以使用Promise.all() ,但是您需要“承诺化” fitbit函数,该函数是围绕它们的一个小包装,这将使它们的常规回调方法返回返回的诺言,然后根据回调结果解决或拒绝该诺言。

Some references on creating a promisified wrapper: 有关创建约定的包装的一些参考:

Wrapping Callback Funtions 包装回叫功能

How to promisify? 如何保证?


If you have an async function that accepts a callback to provide the async result such as fs.rename(oldPath, newPath, callback) , then you can "promisify" it like this: 如果您有一个异步函数接受一个回调来提供异步结果,例如fs.rename(oldPath, newPath, callback) ,那么您可以像这样“承诺”它:

function renameP(oldPath, newPath) {
    return new Promise(function(resolve, reject) {
        fs.rename(oldPath, newPath, function(err) {
            if (err) {
                reject(err);
            } else {
                resolve();
            }
        });
    });
};


renameP("orig.txt", "backup.txt").then(function() {
   // successful here
}, function(err) {
    // error here
});

Some promise libraries such as Bluebird have a built in .promisify() method that will do this for you (it will return a function stub that can be called on any function that follows the node.js async calling convention). 一些承诺库(例如Bluebird)具有内置的.promisify()方法,该方法将为您执行此操作(它将返回一个函数存根,可以在遵循node.js异步调用约定的任何函数上调用该函数存根)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM