Захват результата HTML5 FileReader при использовании обещаний в асинхронном режиме

У меня есть приложение Angular 4, в котором я читаю изображение и пытаюсь передать строку base64 в другую переменную, однако у меня возникла проблема из-за асинхронного характера этого - image.src пуст, и поэтому значение правильно передано в объект изображения?

ngAfterViewInit(): void {
    let image = new Image();
    var promise = this.getBase64(fileObject, this.processImage());
    promise.then(function(base64) {
        console.info(base64);    // outputs string e.g 'data:image/jpeg;base64,........'
    });

    image.src = base64; // how to get base64 string into image.src var here??

    let editor = new PhotoEditorSDK.UI.ReactUI({
        container: this.editor.nativeElement
        editor: {
           image: image
        }
    });
}

/**
 * get base64 string from supplied file object
 */
public getBase64(file, onLoadCallback) {
    return new Promise(function(resolve, reject) {
        var reader = new FileReader();
        reader.onload = function() { resolve(reader.result); };
        reader.onerror = reject;
        reader.readAsDataURL(file);
    });
}

public processImage() {

}

Почему бы вам просто не поместить let image = new Image(); и image.src = base64; в функцию обратного вызова обещания?

sloth 16.11.2018 13:56

Перенести его на promise.then или использовать async await? В чем проблема на +400 ???

yurzui 16.11.2018 14:07

Итак, вы хотите использовать обещание, но не хотите ждать, пока оно будет выполнено.

zaheer 16.11.2018 14:21
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
7
3
1 329
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

promise.then((base64: string) => {
    console.info(base64);    // outputs string e.g 'data:image/jpeg;base64,........'
    console.info(typeof base64); // type is string
    image.src = base64;

    let editor = new PhotoEditorSDK.UI.ReactUI({
        container: this.editor.nativeElement
        editor: {
           image: image
        }
    });
});

Редактировать: Я изменил функцию обратного вызова на функцию толстой стрелки () => {}, потому что вы получаете доступ к одному из полей компонента с помощью this.editor, а function имеют свою собственную область действия. Вы можете получить сообщение об ошибке cannot read nativeElement of undefined.

Кажется, работает, однако я получаю Type '{}' is not assignable to type 'string', хотя уверен, что переменная base64 является строкой. Я также объявил изображение как любое, например, public image: any - по какой причине я получаю ошибку машинописного текста в моем редакторе? (хотя вроде работает ...)

Zabs 16.11.2018 15:54

Вы можете явно определить base64 как строку, так как вы знаете, что это будет строка во время выполнения. Так что попробуйте function(base64: string)

Bunyamin Coskuner 16.11.2018 15:59
Ответ принят как подходящий

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

ngAfterViewInit(): void {
   let image = new Image();
   var promise = this.getBase64(this.fileObject, this.processImage);
   promise.then(function(base64: string) {
       console.info(base64);    
       image.src = base64;

       let editor = new PhotoEditorSDK.UI.ReactUI({
           container: this.editor.nativeElement
           editor: {
             image: image
           }
       });
   });
}

Я изменил следующее:

  1. Я переместил код для создания экземпляра ReactUI в обратный вызов обещания
  2. Указан тип параметра base64 как string
  3. Исправлена ​​опечатка в вызове функции getBase64, от this.processImage() к this.processImage, поэтому он передает функцию обратного вызова, а не результат функции processImage.

Надеюсь, это поможет!

Поскольку getBase64 - это асинхронная операция, вы не можете сразу использовать ее результат. Вам нужно дождаться этого, либо позвонив в then (как вы уже экспериментировали), либо используя async/await.

Версия async/await (которая также является частью стандарта es 2017) проще для понимания, особенно если вы новичок в асинхронном программировании. Общее практическое правило: если вы видите Promise и вам нужно использовать значение, вам нужно будет использовать оператор await (и сделать свой метод асинхронным)

async ngAfterViewInit() {
    let image = new Image();
    var base64 = await this.getBase64(fileObject, this.processImage());

    image.src = base64; //Now available

    let editor = new PhotoEditorSDK.UI.ReactUI({
        container: this.editor.nativeElement
        editor: {
           image: image
        }
    });
}
public getBase64(file, onLoadCallback) {
    return new Promise<string>(function(resolve, reject) {
        var reader = new FileReader();
        reader.onload = function() { resolve(reader.result as string); };
        reader.onerror = reject;
        reader.readAsDataURL(file);
    });
}

Вы также можете переместить свой код в обратный вызов, переданный вызову then, но это может быть немного сложнее для чтения (особенно, если вы только начинаете с асинхронным кодом), и если вам нужно организовать несколько асинхронных операций, чтение кода быстро становится проблема

async ngAfterViewInit() {
    let image = new Image();
    this.getBase64(fileObject, this.processImage())
        .then(base64=>
        {
            image.src = base64; // available now 

            let editor = new PhotoEditorSDK.UI.ReactUI({
                container: this.editor.nativeElement
                editor: { image }
            });
        });
}

Другие вопросы по теме