Как использовать Promise.all в реакции JS ES6

-2

Я хочу, чтобы загрузить файл на сервер, а затем получить URL-адрес загруженного файла и просмотреть его. Файлы могут быть более одного. Для этого я написал следующий код:

 let filesURL=[];
 let promises=[];
 if(this.state.files_to_upload.length>0) {

    for(let i=0; i<this.state.files_to_upload.length; i++) {
        promises.push(this.uploadFilesOnServer(this.state.files_to_upload[i]))
    }

    Promise.all(promises).then(function(result){
        console.log(result);
        result.map((file)=>{
            filesURL.push(file);
        });
    });
    console.log(filesURL);
}
const uploadedFilesURL=filesURL;
console.log(uploadedFilesURL);

console.log(filesURL); дайте мне значения, возвращенные Promise.all.
И я хочу использовать эти значения только тогда, когда Promise.all завершится правильно. Но я столкнулся с проблемой, что строки console.log(uploadedFilesURL); excuz первый независимо от Promise.all и дать мне undefined values.I думаю, что я не использую обещания правильно, может кто-нибудь, пожалуйста, помогите мне?
Код uploadFileOnServer:

uploadFilesOnServer(file)
  {
    let files=[];
    let file_id='';

    const image=file;
    getImageUrl().then((response) => {
      const data = new FormData();
      data.append('file-0', image);
      const {upload_url}  = JSON.parse(response);
      console.log(upload_url);

      updateProfileImage(upload_url, data).then ((response2) => {
      const data2 = JSON.parse(response2);
      file_id=data2;
      console.log(file_id);
      files.push(file_id);
      console.log(files);
        });
    });
    return files;
  }
  • 0
    Вам нужно больше узнать об обещаниях в Javascript. Прежде всего, console.log(uploadedFilesURL); будет выполнен немедленно. Код, который необходимо выполнить после разрешения обещания, .then() обратный вызов .then() . Во-вторых, Promise.all() принимает в качестве аргумента массив обещаний, а вы передаете ему массив любого типа file_id .
  • 0
    Возможный дубликат Как я могу вернуть ответ от асинхронного вызова?
Теги:

3 ответа

2
Лучший ответ

Нет, обещание асинхронно и, как таковое, не работает так, как вы думаете. Если вы хотите выполнить что-то после завершения обещания, вы должны поместить его в обещание, а then обратный вызов. Вот пример, основанный на вашем коде:

uploadFilesOnServer(file) {
  let files=[];
  let file_id='';

  const promise = getImageUrl()
  .then((imageUrlResponse) => {
    const data = new FormData();

    data.append('file-0', file);

    const { upload_url }  = JSON.parse(imageUrlResponse);

    console.log(upload_url);

    return updateProfileImage(upload_url, data);
  })
  .then ((updateImageResponse) => {
    file_id= JSON.parse(updateImageResponse);

    console.log(file_id);

    files.push(file_id);

    console.log(files);

    return files;
  });

  return promise;
}

let filesPromise = Promise.resolve([]);

if(this.state.files_to_upload.length > 0) {
  const promises = this.state.files_to_upload.map((file) => {
    return this.uploadFilesOnServer(file);
  });

  filesPromise = Promise.all(promises).then((results) => {
    console.log(results);

    return [].concat(...results);
  });
}

// This is the final console.log of you (console.log(uploadedFilesURL);)
filesPromise.then((filesUrl) => console.log(filesUrl));

Хорошая книга, посвященная ES6 вообще и обещаниям, в частности, эта книга. Понимание ECMAScript 6 - Николас К. Закас

Редактировать:

Вот простое объяснение кода примера:

  1. UploadFilesOnServer - это функция, которая берет файл, загружает его и возвращает URL-адрес файла, когда загрузка завершается в будущем в виде обещания. Обещание будет вызывать его then обратный вызов, когда он получает URL.

  2. Используя функцию map, мы создаем список обещаний url, результаты, которые мы получили от выполнения uploadFilesOnServer для каждого файла в списке.

  3. Метод Promise.all ожидает выполнения всех обещаний в списке, присоединяется к списку результатов URL и создает обещание с результатом, который является списком адресов. Нам это нужно, потому что нет гарантии, что все обещания будут завершены сразу, и нам нужно собрать все результаты в один обратный вызов для удобства.

  4. Мы получаем ссылки из then обратного вызова.

  • 0
    Большое спасибо @ Tr1et. Ваш данный фрагмент кода решает проблему. Что я понимаю выше, так это то, что сначала мы отображаем массив «files_to_upload» на «file» и передаем его «uploadFileOnServer». Эта функция возвращает обещание с массивом «files». Затем вы вызываете обещание. Каждое обещание и объединяете все данные в один массив. Теперь «filePromise» будет иметь все объединенные данные, и он будет доступен в целом «.then ()» из filePromise. Пожалуйста, скажите мне, правильно ли я понимаю, или поправьте меня, где я ошибаюсь. Спасибо.!
  • 0
    Я добавил объяснение в ответ, потому что это довольно долго. Есть что-то, чего ты не понимаешь?
Показать ещё 1 комментарий
3

Вы должны сделать это на .then части вашего Promise.all()

Promise.all(promises)
.then(function(result){
   console.log(result);
   result.map((file)=>{
     filesURL.push(file);
   });
   return true; // return from here to go to the next promise down
 })
 .then(() => {
     console.log(filesURL);
     const uploadedFilesURL=filesURL;
     console.log(uploadedFilesURL);
 })
0

Так работает асинхронный код. Вы не можете ожидать свой console.log(filesURL); правильно работать, если он называется синхронно после асинхронного вызова для извлечения файлов с сервера.

Что касается вашего кода, то есть несколько проблем:

1. uploadFilesOnServer должен возвращать Promise, поскольку он isync. Следовательно:

  uploadFilesOnServer(file)
  {
    let files=[];
    let file_id='';

    const image=file;
    return getImageUrl().then((response) => {
      const data = new FormData();
      data.append('file-0', image);
      const {upload_url}  = JSON.parse(response);
      console.log(upload_url);

      updateProfileImage(upload_url, data).then ((response2) => {
      const data2 = JSON.parse(response2);
      file_id=data2;
      console.log(file_id);
      files.push(file_id);
      console.log(files);
      return files;
        });
    });
  }

2. Внутри основного тела функции вы можете оценивать результаты выполнения Promise.all только в соответствующем handler.

В качестве дополнительной заметки я бы посоветовал вам использовать функции es7 async/await с некоторыми транспилерами, такими как babel/typescript. Это значительно сократит вложенность/осложнения при написании такого кода.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню