Как использовать обещания в цикле и убедиться, что все выполнено, прежде чем продолжить? - PullRequest
0 голосов
/ 25 апреля 2018

Я использую библиотеку localforage для доступа к localStorage / IndexedDB. Чтобы извлечь элемент, вызывается функция localforage.getItem (), которая возвращает Promise, который выполняется при получении данных.

Мне нужно перебрать ключи localforage, вызвать 'getItem' для любого ключа, который соответствует моим критериям, и поместить значение этого ключа в массив 'совпадений'. Однако я не хочу продолжать работу до тех пор, пока не буду уверен, что все значения были успешно добавлены в «совпадения».

Я довольно новичок в Обещаниях, и я не могу понять, как ждать, пока все обещания getItem () не будут выполнены, прежде чем я продолжу.

Я понимаю, что у localforage есть функция 'iterate', но я действительно заинтересован в том, чтобы стать более опытным в использовании Promises, и очень хотел бы знать, как это должно работать.

Вот что я делаю:

var matches = [];  // Array to store matched items

localforage.keys()  // Get all keys in localforage
    .then(function(keys)  // When all keys are retrieved, iterate:
    {
        for(var i in keys)
        {
            // If the current key matches what I am looking for, add it to the 'matches' array.
            if (keys[i].indexOf('something i am looking for') > -1)
            {
                // Here I need to add this value to my array 'matches', but this requires using the getItem method which returns a Promise and doesn't necessarily fulfill immediately.
                localforage.getItem(keys[i])
                    .then(function(value)
                    {
                        matches.push(value);
                    });
              }
          }
      });

// At this point, I want to proceed only after *all* matches have been added to the 'matches' array (i.e. the getItem() Promises are fulfilled on all items in the loop).

Как мне это сделать? Здесь применяется выражение «ожидание»? Например, я должен сделать

await localforage.getItem(keys[i])
    .then(function(value)
    ... etc

Это сделает функцию getItem синхронной?

Спасибо за любые предложения / указатели.

1 Ответ

0 голосов
/ 25 апреля 2018

Вы можете использовать Promise.all() в этой ситуации.Основная идея состоит в том, что вы помещаете кучу обещаний в массив, а затем передаете этот массив в Promise.all(), когда все обещания в массиве разрешаются, Promise.all() разрешается в массив значений:

localforage.keys()  
    .then(function(keys){  
        var matches = []
        for(let i in keys) {
            if (keys[i].indexOf('something i am looking for') > -1) {
                // matches will be an array of promises
                matches.push(localforage.getItem(keys[i]))
            }
        }
        // Promise.all returns a promise that resolves to an array 
        // of the values they resolve to
        return Promise.all(matches)
    })
    .then(values => {
        // values is an array of your items
    })

Вы можете использовать async/await для этого тоже с чем-то подобным с отключенными keys и getItems, чтобы запустить фрагмент:

let localforage = {
  keys() {
    return Promise.resolve([1, 2, 3, 4, 5])
  },
  getItem(k) {
    return Promise.resolve("found: " + k)
  }
}


async function getStuff() {
  let matches = []
  let keys = await localforage.keys()
  for (let key of keys) {
    matches.push(await localforage.getItem(key))
  }
  return matches
}

getStuff()
  .then(values => {
    console.log(values)
  })
...