Рекурсивное использование async/await с пакетом запроса узла

Я делаю http-запрос, используя библиотеку узлов response, и пытаюсь вызвать его рекурсивно (если пользователь сделал фиксацию в один день, проверьте предыдущий день. Если нет, подсчитайте все дни, чтобы получить полосу).

Проблема в том, что линия

const githubResponse = await request(options);

Выдает ошибку

Unexpected token o in JSON at position 1

await request(options), похоже, не возвращает ответ JSON GitHub API, который я ожидаю, но вместо этого githubResponse кажется объектом, который я не могу использовать. Я предполагаю, что неправильно использую async/await, но не знаю, как это исправить.

async function checkUserCommitForDate(user, date) {
    const options = {
        url: `https://api.github.com/search/commits?q=author:${user}+author-date:${date}`,
        headers: {
            'User-Agent': 'request',
            'Accept': 'application/vnd.github.cloak-preview'
        }
    };
    const githubResponse = await request(options)

    // I get an error on the next line

    if (JSON.parse(githubResponse).total_count > 0) {
        const previousDaysDate = moment(date).subtract(1, 'day').format('YYYY-MM-DD');
        let streakCounter = await checkUserCommitForDate(user, previousDaysDate);
        streakCounter++;
        console.log('streakCounter', streakCounter);
        return streakCounter;
    } else {
        return 0;
    }
}

ОБНОВЛЕНИЕ: похоже, это не обещание, поэтому мне нужно отформатировать это по-другому (как обратный вызов). Когда я пытаюсь это:

async function checkUserCommitForDate(user, date) {
    const options = {
        url: `https://api.github.com/search/commits?q=author:${user}+author-date:${date}`,
        headers: {
            'User-Agent': 'request',
            'Accept': 'application/vnd.github.cloak-preview'
        }
    };
    request(options, async function (error, response, body) {
        console.log('error:', error); // Print the error if one occurred
        if (JSON.parse(body).total_count > 0) {
            const previousDaysDate = moment(date).subtract(1, 'day').format('YYYY-MM-DD');
            let streakCounter = await checkUserCommitForDate(user, previousDaysDate);
            streakCounter++;
            console.log('streakCounter', streakCounter);
            return streakCounter;
        } else {
            return 0;
        }
    });
}

Линия

let streakCounter = await checkUserCommitForDate(user, previousDaysDate);

становится проблемой, поскольку streakCounter не определено, что делает журнал NaN.


person Luke Schlangen    schedule 20.10.2017    source источник
comment
Возможно, вы используете модуль request, а не response? Если это так, он не возвращает обещание, а использует обратный вызов.   -  person alexmac    schedule 21.10.2017
comment
что такое гитубответ? вы когда-нибудь console.log перед попыткой разобрать?   -  person Johannes Merz    schedule 21.10.2017
comment
В обновлении, когда я логирую тело, я получаю JSON, а когда я его разбираю, я получаю объект, просто я все еще не возвращаю номер, потому что есть новая проблема.   -  person Luke Schlangen    schedule 21.10.2017
comment
Я не думаю, что вы можете использовать await/async с обратными вызовами, они работают с промисами. Пакет запроса использует обратные вызовы, которые делают async/await недоступными для использования, поскольку вы не можете ничего вернуть из обратного вызова.   -  person codejockie    schedule 21.10.2017
comment
поэтому мне нужно отформатировать это по-другому (как обратный вызов). - Нет. Поэтому вам нужно дать обещание. Или просто используйте пакет request-promise вместо request.   -  person Bergi    schedule 21.10.2017


Ответы (3)


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

Использование его в вашем коде должно работать прямо из коробки с async/await

person Enrique Fueyo    schedule 21.10.2017

Я использовал пример обещания отсюда, чтобы преобразовать его в это, и это сработало!

async function checkUserCommitForDate(user, date) {
    const options = {
        url: `https://api.github.com/search/commits?q=author:${user}+author-date:${date}`,
        headers: {
            'User-Agent': 'request',
            'Accept': 'application/vnd.github.cloak-preview'
        }
    };

    const githubResponse = await promisify(request)(options);

    if (JSON.parse(githubResponse.body).total_count > 0) {
        const previousDaysDate = moment(date).subtract(1, 'day').format('YYYY-MM-DD');
        let streakCounter = await checkUserCommitForDate(user, previousDaysDate);
        streakCounter++;
        console.log('streakCounter', streakCounter);
        return streakCounter;
    } else {
        return 0;
    }
}

function promisify(fn) {
    return function (...args) {
        return new Promise((resolve, reject) => {
            fn(...args, (err, result) => {
                if (err) return reject(err);
                resolve(result);
            });
        });
    };
};
person Luke Schlangen    schedule 20.10.2017
comment
уже существует модуль request-promise (github.com/request/request-promise), который обрабатывает ваш запрос обещание - person Enrique Fueyo; 21.10.2017
comment
Спасибо Энрике! Если вы хотите создать ответ с этим, я отмечу его как правильный. - person Luke Schlangen; 21.10.2017

Если вы обновились до Node 8 LTS, можно использовать собственный util.promisfy, как показано ниже:

const { promisify } = require('util')
const request = promisify(require('request'))

async function checkUserCommitForDate(user, date) {
  const options = {
    url: `https://api.github.com/search/commits?q=author:${user}+author-date:${date}`,
    headers: {
      'User-Agent': 'request',
      'Accept': 'application/vnd.github.cloak-preview',
      'json':true
    }
  };

  try{
    const githubResponse = await request(options);
    if (githubResponse.body.total_count > 0) {
      const previousDaysDate = moment(date).subtract(1, 'day').format('YYYY-MM-DD');
      let streakCounter = await checkUserCommitForDate(user, previousDaysDate);
      streakCounter++;
      console.log('streakCounter', streakCounter);
      return streakCounter;
    } else {
        return 0;
    }
  }
  catch(err){
    console.error(err)
    return 0;
  }
}

Использование json:true в параметрах сократит еще один этап анализа, поскольку ответ будет в формате JSON.

person Nagaraja Malla    schedule 16.11.2017