Angular - асинхронный метод не возвращает отклоненное обещание - PullRequest
0 голосов
/ 23 октября 2018

Я использую метод async в компоненте для загрузки файла.Например:

//component
uploadPhotos = async (event: Event) => {
    const upload = await this.uploadService.uploadPhotos(event, this.files, this.urls);
}

UploadService возвращает promise с обновленными файлами и путями после вызова загрузки.Служба работает, как ожидается, для promise, который достигает resolve() без каких-либо задержек.Однако, если вызывается reject(), код будет продолжать работать до тех пор, пока не достигнет resolve() внутри reader.onload().

// service
uploadPhotos(event: Event, oldFiles: File[], oldUrls: string[]): Promise<{files: File[], urls: string[]}> {
     return new Promise((resolve, reject) => {
          const files = (event.target as HTMLInputElement).files;

          if ((files.length + oldFiles.length) > 5) {
               this.alertService.error('Número máximo de fotos permitidos é 5.');
               reject();
               // there is an error, so it reaches here first
          }
      
          for (let i = 0; i < files.length; i++) {
              const exists = oldFiles.findIndex(file => file.name === files[i].name);
              if (exists === -1) {
                   if (files[i].type === 'image/png' || files[i].type === 'image/jpeg') {
                      oldFiles.push(files[i]);

                      const reader = new FileReader();
                      reader.onerror = (error: any) => {
                          this.alertService.error(`Erro ao carregar a imagem: ${error}`);
                          reject();
                      };
                      reader.readAsDataURL(files[i]);
                      reader.onload = () => {
                      // it reaches here after reject()
                          oldUrls.push(reader.result);
                          if (i === files.length - 1) { resolve({ files: oldFiles, urls: oldUrls }); }
                 };
            } else {
                this.alertService.error('Formato inválido. Somente imagens do formato Png, Jpeg e Jpg são permitidos.');
                reject();
            }
       }
  }
});
}

Есть ли способ избежать этого блока reader.onload(), если reject() достигнут до resolve()?

Ответы [ 2 ]

0 голосов
/ 23 октября 2018

Да, reject() и resolve() - это простые (обратные вызовы) вызовы функций.Они не имеют ничего общего с потоком управления, они не останавливают вашу функцию.Для этого используйте return или if / else.

Кроме того, внутри вашего new Promise есть петля.Если в одном из файловых ридеров происходит ошибка, это не влияет на другие файловые ридеры.Вместо этого я рекомендую обещание на самом внутреннем уровне.Затем напишите

readFile(file: File): Promise<string> {
    return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onerror = (error: any) => reject(error);
        reader.onload = () => resolve(reader.result);
        reader.readAsDataURL(file);
    });
}
// service
async uploadPhotos(event: Event, oldFiles: File[], oldUrls: string[]): Promise<{files: File[], urls: string[]}> {
    try {
        const files = (event.target as HTMLInputElement).files;
        if ((files.length + oldFiles.length) > 5) {
            throw new Error('Número máximo de fotos permitidos é 5.');
        }
        const newFiles = Array.from(files).filter(newFile =>
            !oldFiles.some(oldFile => oldFile.name === newFile.name)
        );
        if (!newFiles.every(file => file.type === 'image/png' || file.type === 'image/jpeg' || file.type === 'image/jpg')) {
            throw new Error('Formato inválido. Somente imagens do formato Png, Jpeg e Jpg são permitidos.');
        }
        const newUrls = await Promise.all(newFiles.map(file =>
            this.readFile(file).catch(error => {
                throw new Error(`Erro ao carregar a imagem: ${error}`);
            })
        ));
        return {
            files: oldFiles.concat(newFiles),
            urls: oldUrls.concat(newUrls)
        };
    } catch(err) {
        this.alertService.error(err.message);
        throw new Error("something went wrong during file upload");
    }
}
0 голосов
/ 23 октября 2018

Вы можете добавить прослушиватель load, а затем удалить его в обработчике error, чтобы прослушиватель load не запускал:

reader.onerror = (error: any) => {
  this.alertService.error(`Erro ao carregar a imagem: ${error}`);
  reader.removeEventListener('load', loadHandler);
  reject();

};
reader.readAsDataURL(files[i]);
const loadHandler = () => {
  oldUrls.push(reader.result);
  if (i === files.length - 1) {
    resolve({ files: oldFiles, urls: oldUrls });
  }
};
reader.addEventListener('load', loadHandler);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...