массив из рекурсивного запроса на выборку не возвращается должным образом

Я пытаюсь изучить разбиение на страницы на основе курсора с помощью Slack API. Моя цель — вернуть массив всех сообщений с помощью метода channel.history.

У меня есть функция рекурсивной выборки javascript, но я не могу заставить локальную переменную "final" правильно вернуться.

Часть, в которой он регистрирует «успешные результаты разбивки на страницы», регистрирует и возвращает массив, как и ожидалось, с длиной 204.

Когда "final" вызывается за пределами этой области, длина равна 0.

Я пытался поэкспериментировать с тем, где я возвращаю переменную final, но не могу заставить ее работать. Я думаю, что это связано с тем, что функция обратного вызова не используется, но я не знал, где это реализовать.

Вот что у меня есть (с удаленным токеном Slack).

function paginate() {
  let final = [];

  let selectChannel = function(ts) {
    fetch('https://slack.com/api/channels.history?token=MY_TOKEN&channel=C6W9FH2S0&latest=' + ts)
      .then(response => response.json())
      .then(responseData => {
        let messages = responseData.messages;
        if (!responseData.has_more) {
          final.push.apply(final, messages);
          console.log('Pagination results successfull, 204 items in the array!', final);
          return final;
        } else {
          final.push.apply(final, messages);
          selectChannel(messages[messages.length - 1].ts);
        }
        return final;
      })
      .catch(error => {
        console.log('Error fetching and parsing data', error);
      });
  }

  selectChannel(new Date());
  // Returning as 0, when I am expecting 204
  console.log("Final Output", final.length);
  return final;
}


var x = paginate();
// By extention, this is returning as 0, when I am expecting 204 as well
console.log("Output", x.length);

person DJBrandoK    schedule 24.09.2017    source источник
comment
выборка асинхронная...   -  person Hitmands    schedule 24.09.2017
comment
final — очень-очень плохое имя для переменной.   -  person Sainan    schedule 24.09.2017
comment
Честно говоря, это экспериментальный проект, поэтому я не тратил время на присвоение имен переменным. Выход, вероятно, лучшая идея. Я думал, что .then относится к асинхронному аспекту. Также спс за быстрые ответы.   -  person DJBrandoK    schedule 24.09.2017
comment
Пожалуйста, взгляните на этот stackoverflow.com/questions/14220321/   -  person palaѕн    schedule 24.09.2017


Ответы (1)


Это потому, что код внутри функции then выполняется позже (привет, async await :).

fetch() возвращает обещание выполнить какой-то момент в будущем, и to может вернуть это обещание и добавить еще один метод then() и там console.log()

Вот ваши блоки кода в порядке выполнения, это может прояснить ситуацию:

function paginate() {  /* 2 */
  let final = [];

  let selectChannel = function(ts) { /* 4 */
    fetch('https://slack.com/api/channels.history?token=MY_TOKEN&channel=C6W9FH2S0&latest=' + ts)
      .then(response => response.json() /* 8 */)
      .then(responseData => { /* 9 */
        let messages = responseData.messages;
        if (!responseData.has_more) {
          final.push.apply(final, messages);
          console.log('Pagination results successfull, 204 items in the array!', final);
          return final;
        } else {
          final.push.apply(final, messages);
          selectChannel(messages[messages.length - 1].ts);
        }
        return final;
      })
      .catch(error => { /* 10 */
        console.log('Error fetching and parsing data', error);
      });
  }

  selectChannel(new Date()); /* 3 */
  // Returning as 0, when I am expecting 204
  console.log("Final Output", final.length); /* 5 */
  return final; /* 6 */
}


var x = paginate(); /* 1 */
// By extention, this is returning as 0, when I am expecting 204 as well
console.log("Output", x.length); /* 7 */

Как вы можете видеть, шаг 7 регистрирует результат x.length, в то время как только на шаге 9 этот результат окончательно заполняется (конечная переменная заполняется в шаге/блоке кода 9)

В асинхронном мире ваш код будет (должен) выглядеть так:

async function selectChannel() {
    try {
        var response = await fetch('https://slack.com/api/channels.history?token=MY_TOKEN&channel=C6W9FH2S0&latest=' + ts);
        var responseData = await response.json();
        let messages = responseData.messages;
        if (!responseData.has_more) {
            final.push.apply(final, messages);
            console.log('Pagination results successfull, 204 items in the array!', final);
            return final;
        } else {
            final.push.apply(final, messages);
            await selectChannel(messages[messages.length - 1].ts);
        }
        return final;
    } catch (error) {
        console.log('Error fetching and parsing data', error);
    }
}

async function execute() {
    var finalData = await selectChannel(new Date());
    console.log("Final Output", finalData.length);
}

execute() // optionally: .then(x=> console.log('we are finished executing!'));
person Joel Harkes    schedule 24.09.2017
comment
спасибо за подробный ответ и объяснение (все еще перечитываю, чтобы понять. Мне пришлось добавить аргумент ts для selectChannel и заставить функцию выполнения возвращать finalData, чтобы заставить ее возвращать кого-то за пределами selectChannel. Теперь она возвращает 100, когда Я надеюсь, что он вернет 204. Вы ответили на мой вопрос, но теперь мне нужно выяснить, почему он принимает данные только для первого вызова выборки, а не действует рекурсивно.Большое спасибо!! - person DJBrandoK; 24.09.2017
comment
Я изменил предоставленный вами код и добился своей цели, используя этот jsfiddle.net/gp6f8Lyv. - person DJBrandoK; 24.09.2017