Реструктуризация для асинхронных операций - PullRequest
0 голосов
/ 19 марта 2020

Мне трудно заставить мой код работать в правильной последовательности. Мне действительно нужно понять, как правильно использовать обещания. Я прочитал вопрос «Как вернуть ответ от асинхронного вызова?»:

Как вернуть ответ от асинхронного вызова?

Все ответы вращаются вокруг запросов XHR и подобных. Я использую класс Image () в Javascript, чтобы получить разрешение из файлов JPEG. Это функция, которая выбирает массив файлов с моего сервера, а затем для каждого добавляет в массив идентификатор и разрешение. Единственное, что мне нужно для Image () - это вернуть ширину и высоту, но мне нужен мой код, чтобы дождаться его завершения до 1057 *, прежде чем двигаться дальше.

У меня тоже есть эта проблема в других местах и мой проект становится нестабильным. Я думаю, это потому, что все происходит не в правильной последовательности.

Я действительно изо всех сил пытаюсь понять, как реструктурировать мой код так, чтобы он ожидал, пока объект Image () прочитает из файла и вернет свое разрешение, прежде чем он выключится и использует упомянутую информацию (которой там нет). ).

Полагаю, причина, по которой этот вопрос отличается от упомянутого выше, заключается в том, что мне не нужно выполнять никаких операций с данными в обещании, кроме их извлечения. Если бы это был запрос XHR, я мог бы ответить. Отправить его, а если бы это был массив, я бы мог Array.filter, но это не так, и мне просто нужно его вернуть.

Вот мой код: getJpegs возвращает массив файлов с сервера.

export const getJpegs = async () => {
  return await fetch(apiUrl + 'getjpegs')
  .then( async response => {
    if (response.ok) return await response.json()
    else return await response.text()
  })
  .then( async responseData => {
    let newJpegs = await responseData.map( **async** (file, i) => {
      const img = **await** new Image()
      img.src = imageUrl + file
      return {
        file: file,
        id: i,
        res: {
          width: img.width, 
          height: img.height
        }
      }
    })
    return newJpegs;
  })
  .catch(err => console.log('ERROR!!!', err))
}

Если я удаляю асин c и ожидаю, что теги, которые я выделил, работает, за исключением случаев, когда сначала вы загружаете страницу, значения ширины и высоты не определены, пока вы не обновите ее sh. С их помощью значения ширины и высоты определяются как выполненное обещание, а не значения, которые мне нужны!

Как мне go изменить структуру этого кода для достижения того, чего я хочу?

Спасибо.

...

Хорошо, я тоже попробовал:

export const getJpegs = async () => {
  return await fetch(apiUrl + 'getjpegs')
  .then( async response => {
    if (response.ok) return await response.json()
    else return await response.text()   
  })
  .then( async responseData => {
    let newJpegs = await responseData.map( (file, i) => {

      let dimensions = {};
      const img = new Image()
      img.onload( () => {
        dimensions = {   
          width: img.width,
          height: img.height
        }
      })
      img.src = imageUrl + file

      return {     
        file: file,   
        id: i,   
        res: dimensions     
      }
    })
    return newJpegs;
  })
  .catch(err => console.log('ERROR!!!', err))
}

Как мне заставить его ждать?

ОБНОВЛЕНИЕ

Спасибо @Supercool, этот вопрос, безусловно, очень похож на мой. Разница лишь в том, что я использую объект Image () вместо второго обещания fetch ().

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

export const getJpegs = async () => {
return await fetch(apiUrl + 'getjpegs')
.then( async response => {
  if (response.ok) return await response.json()
  else return await response.text()
})
.then( async responseData => {
  let newJpegs = [];
  await Promise.all(responseData.map( async (file, i) => {
    const img = await new Image()
    await img.addEventListener('load', () => {
      newJpegs.push({
        file: file,
        id: i,
        res: { width: img.width, height: img.height }
      })
    })
    img.src = "./images/resize300/" + file
  }))
  console.log(newJpegs)
  return newJpegs;
})

Он все еще не ожидает должным образом, хотя в конце файла console.log он выводит массив со всеми правильными данными, но с остальными программа просто продолжает, как если бы массив был пустым. Я предполагаю, что это обновляет память после того, как она проходит через остальную часть программы!

Если я вместо этого console.log (JSON .stringify (newJpegs)) вы просто увидите пустой массив ("[]"), чтобы подтвердить, что он все еще не ждет !!

Будут с благодарностью приняты любые другие предложения,

Спасибо.

ОБНОВЛЕНИЕ

Хорошо, я решил проблему для всех, кто заинтересован. Проблема заключалась в том, что и метод Array.map (), и функция обратного вызова, которую он возвращает (с экземпляром Image () в), должны быть заключены в обещание. Вот рабочий код:

export const getJpegs = async () => {
  return await fetch(apiUrl + 'getjpegs')
  .then( async response => {
    if (response.ok) return await response.json()
    else return await response.text()
  })
  .then( async responseData => {
    let newJpegs = [];
    await Promise.all(responseData.map( (file, i) => {
      return new Promise((resolve, reject) => {
        const img = new Image()
        img.addEventListener('load', () => {
          resolve({
            file: file,
            id: i,
            res: { width: img.width, height: img.height }
          })
        })
        img.src = "./images/resize300/" + file
      }).then( response => newJpegs.push(response) )
    }))
    console.log(newJpegs)
    return newJpegs;
  })
.catch(err => console.log('ERROR!!!', err))
}

Спасибо за вашу помощь.

...