Есть ли способ дождаться завершения функции? - PullRequest
0 голосов
/ 29 января 2019

Я пытаюсь получить информацию (true / false) из AsyncStorage в функции и создать строку, которая важна для получения данных на следующем шаге.Моя проблема в том, что функция не завершена, пока строка не требуется.

Я пробовал многие решения из Интернета, такие как асинхронная функция, и ожидаю getItem или .done () или .then (), но ни одно не сработало длямне.

Текущее поведение таково, что консоль отображает первый «требуемый канал:», чем «channel: channel_id0».

Ответы [ 3 ]

0 голосов
/ 30 января 2019

Попробуйте вместо этого.Асинхронные функции и обещания могут быть сложными для получения правильных результатов и могут быть сложными для отладки, но вы на правильном пути.

async _getFetchData() {
    let channels = "";

    let results = await AsyncStorage.getAllKeys();

    results.forEach((result) => {
        if (result.includes("not") === false) {
            let item = await AsyncStorage.getItem(result);

            if (item === 'true') {
                console.log(`channel: ${result}`)

                channels = `channel_id ${result}`;
            }
        }
    });

    return channels;
}

_fetchData() {
    this._getFetchData().then((channels) => {
        console.log(`channel required: ${channel}`);
    });
}
0 голосов
/ 30 января 2019

Аспекты в вашем вопросе неясны:

  1. Вы не говорите, когда установлен this.state.firstValue, и как это связано с тем, что вы пытаетесь достичь.

  2. У вас есть for-loop, где вы можете установить одно и то же значение несколько раз.

  3. Вы изменяете состояние, а не устанавливаете его.Это не хорошо, см. Этот ТАК вопрос , чтобы узнать больше об этом.

Мы можем кое-что сделать, чтобы ваш код было легче понять.Ниже я покажу возможный рефакторинг.Объясняя, что я делаю на каждом этапе.Я использую async/await, потому что это может привести к гораздо более аккуратному и легкому чтению кода, вместо использования promises, где вы можете потеряться в обратных вызовах.

  1. Получить все ключи из AsyncStorage
  2. Убедитесь, что есть значение для всех ключей.
  3. Отфильтруйте ключи так, чтобы мы включали только те, которые не содержат строку 'not'.
  4. Используйте Promise.all, эта часть важна, поскольку она в основном получает все значения длякаждый из ключей, которые мы только что нашли, и помещает их в массив с именем items
  5. Каждый объект в массиве items имеет свойства key и value.
  6. Затем мы фильтруем items так, чтобы остались только те, у которых item.value === 'true'.
  7. Затем мы фильтруем items, чтобы остались только те, у которых item.value !== 'true'.(это может быть необязательным, это действительно зависит от того, что вы хотите сделать)
  8. Что мы возвращаем?Вам нужно добавить эту часть.

Вот рефакторинг:

_getFetchData = async () => {
  let allKeys = await AsyncStorage.getAllKeys();                             // 1
  if (allKeys.length) {                                                      // 2

    let filteredKeys = allKeys.filter(key => !key.includes('not'));          // 3
    let items = await Promise.all(filteredKeys.map(async key => {            // 4
      let value = await AsyncStorage.getItem(key);
      return { key, value };                                                 // 5
    }))

    let filteredTrueItems = items.filter(item => items.value === 'true');    // 6
    let filteredFalseItems = items.filter(item => items.value !== 'true');   // 7
    // now you have two arrays one with the items that have the true values 
    // and one with the items that have the false values
    // at this points you can decide what to return as it is not 
    // that clear from your question

    // return the value that your want                                       // 8
  } else {
    // return your default value if there are no keys                        // 8
  }
}

Вы бы назвали эту функцию следующим образом:

_fetchData = async () => {
  let channel = await this._getFetchData();
  console.log("channel required: " + channel);
}

Хотя вышебудет работать, в настоящее время он не будет возвращать значение, так как вы не указали, какое значение вы хотите вернуть.Я бы посоветовал вам опираться на код, который я написал здесь, и обновить его, чтобы он возвращал нужные вам значения.

Дополнительное чтение

Для дальнейшего чтения я хотел бы предложить эти удивительные статьи Майкла Чана, в которых обсуждаются state

https://medium.learnreact.com/setstate-is-asynchronous-52ead919a3f0

https://medium.learnreact.com/setstate-takes-a-callback-1f71ad5d2296

https://medium.learnreact.com/setstate-takes-a-function-56eb940f84b6

Я бы также предложил потратить некоторое время, чтобы прочитать о async/await и promises

https://medium.com/@bluepnume/learn-about-promises-before-you-start-using-async-await-eb148164a9c8

И, наконец, этостатья и вопрос SO по Promise.all довольно хороши

https://www.taniarascia.com/promise-all-with-async-await/

Использование async / await с циклом forEach

0 голосов
/ 30 января 2019

что делать, если вы завернули _getFetchData() в обещание?Это позволит вам использовать

var channel = this._getFetchData().then(console.log("channel required: " + channel));

В противном случае console.log не будет ожидать выполнения _getFetchData ().Это то, что сообщает console.log.это просто записывает строку.переменная добавляется после выполнения асинхронной операции.

ОБНОВЛЕНИЕ

Я бы попробовал это:

//_getFetchData()
AsyncStorage.getAllKeys().then((result) => { //get all stored Keys
  valuelength = result.length;
  if (valuelength !== 0) {
    for (let i = 0; i < valuelength; i++) {
      if (result[i].includes("not") == false) { //get Keys without not
        AsyncStorage.getItem(result[i]).then((resultvalue) => {
          if (resultvalue === 'true') {
            if (this.state.firstValue) {
              this.state.channels = this.state.channels + "channel_id" + result[i];
              console.log("channel: " + this.state.channels);
            }
            else {
              this.state.channels = this.state.channels + "channel" + result[i];
            }
          }
        });
      }
return new Promise((resolve, reject) => {
    this.state.channels !=== undefined ? resolve(this.state.channels) : reject(Error('error '));
}

_fetchData() {
var channel = this._getFetchData().then(console.log("channel required: " + channel));
}

возможно, вы должны изменить this.state.channels !=== undefined к выражению, которое соответствует значению по умолчанию this.state.channels.

...