Подтвердить что ты не робот

Являются ли классы JavaScript ES6 для использования с асинхронными кодовыми базами?

Что может ES6 Classes предоставлять в качестве шаблона организации асинхронный код. Ниже приведен пример с ES7 async/await, может ли ES6-класс иметь асинхронный метод или конструктор в ES7?

Можно ли:

class Foo {
    async constructor() {
        let res = await getHTML();
        this.res = res
    }
}

И если нет, то как должен работать конструктор?

class Foo {
    constructor() {
        getHTML().then( function (res) {
            this.res = res
        }
    }
}

Если ни один из этих шаблонов не работает, может ли конструктор (и, кроме того, классы) в ES6 class поддерживать любую форму асинхронности, которая действует на состояние объекта? Или они только для чисто синхронных кодовых баз? Вышеприведенные примеры находятся в конструкторе, но они не должны быть... Нажатие проблемы на еще один уровень.

class Foo {
    myMethod () {
      /* Can I do anything async here */
    }
}

Или с геттером...

class Foo {
    get myProp() {
        /* Is there any case that this is usefully asynchronous */
    }
}

Единственные примеры, о которых я мог подумать, - это запустить что-то параллельно внутри одного и того же метода/конструктора/getter, но чтобы решить эту проблему до конца. Я просто смущен, потому что кажется, что все толчок к полностью асинхронным библиотекам, это просто путает вещи. За исключением примеров учебников, я не могу найти одно приложение, для которого они полезны.

4b9b3361

Ответ 1

Могу ли я сделать async constructor()

Нет, это синтаксическая ошибка - точно так же, как constructor* (). Конструктор - это метод, который ничего не возвращает (без обещаний, без генератора), он только инициализирует экземпляр.

И если не так, как должен работать конструктор, который делает это

Такой конструктор вообще не должен существовать, см. Является ли неправильной практикой, чтобы функция-конструктор возвращала Promise?

Могут ли классы ES6 поддерживать любую форму асинхронности, которая работает в состоянии объекта? Или они только для чисто синхронных кодовых баз?

Да, вы можете использовать асинхронные методы (даже с предлагаемым синтаксисом async) для классов, а getters также могут возвращать promises.

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

Ответ 2

Другим способом, который Классы могут быть полезны для организации асинхронных задач, является использование статических методов.

class Organizer {
    static async foo() {
        const data = await this.bar();
        data.key = value;
        return data;
    }
    static async bar() {
        return {foo:1, bar:2}
    }
};

Organizer.foo();

Конечно, это ничем не отличается от создания простого объектного литерала или нового файла и его включения, за исключением того, что вы можете более чисто extend его.

Ответ 3

ECMAScript 2017 предназначен для классов асинхронных методов.

Вызов другой функции async или обещания - однострочный!

Очень выразительный код читается без перерыва сверху вниз, независимо от отложенного выполнения

Если у вас есть обратные вызовы, альтернативные обработчики ошибок, параллельное выполнение или другие неудовлетворенные потребности, создайте экземпляр promises в теле функции. Лучше иметь код в функциональном теле, а не в исполнителе обещаний, и обратите внимание, что нет кода обратного вызова обертывания try-catch: do there-to-nothing there.

Асинхронный метод может возвращать обещание, регулярное значение или бросать

Обратный вызов apis, который любил Node.js, теперь мы будем ненавидеть со страстью: все они должны быть завернуты в promises

Красота async/await заключается в том, что ошибки пузырятся неявно

class MyClass {
  async doEverything() {
    const sumOfItAll = await http.scrapeTheInternet() +
      await new Promise((resolve, reject) =>
        http.asyncCallback((e, result) => !e ? resolve(result) : reject(e)))
    return this.resp = sumOfItAll
  }
}

Если он ограничен ECMAScript 2015 и без async, возвращайте значения обещания:

class ES2015 {
  fetch(url) {
    return new Promise((resolve, reject) =>
      http.get(url, resolve).on('error', reject))
      .then(resp => this.resp = resp) // plain ECMAScript stores result
      .catch(e => { // optional internal error handler
        console.error(e.message)
        throw e // if errors should propagate
      })
  }
}

Эта версия ECMAScript 2015 - это то, о чем вы действительно спрашиваете, любое желаемое поведение может быть закодировано с помощью построенной конструкции обещания.

Если вы действительно хотите выполнить promises в конструкторе, рекомендуется передать функции then-catch или предоставить некоторую конструкцию обратного вызова, чтобы потребители могли принять меры по выполнению или отклонению обещаний. В конструкторе также рекомендуется подождать nextTick/. Then перед выполнением реальной работы.

Каждое обещание нуждается в финальном улове или будут проблемы

Ответ 4

Это поздний ответ, но причина, по которой ваш второй пример не работает, вызвана контекстной ошибкой. Когда вы передаете function () {} в качестве аргумента Promise.prototype.then(), лексическая this внутри функции будет самой функцией, а не классом. Вот почему установка this.res, кажется, ничего не делает: this в этом случае относится к собственной области функций.

Существует несколько способов доступа к внешнему пространству в Javascript, классическом (который вы видите в коде ES5):

class Foo {
  constructor() {
    var _this = this

    getHTML().then(function (res) {
      _this.res = res
    })
  }
}

Сделав ссылку на класс this, вы можете получить к нему доступ во внутренних областях.

Способ ES6 заключается в том, чтобы использовать функции стрелок, которые не создают новую область действия, а скорее "сохраняют" текущий один.

class Foo {
  constructor() {
    getHTML().then(res => this.res = res)
  }
}

Помимо контекстных проблем, по-моему, это по-прежнему не оптимальный асинхронный шаблон, потому что у вас нет возможности узнать, когда getHTML() закончил или, что еще хуже, потерпел неудачу. Эта проблема решена элегантно с асинхронными функциями. Хотя вы не можете сделать async constructor () { ... }, вы можете инициировать обещание в конструкторе, а await - в функциях, которые зависят от него.

Пример gist свойства async в конструкторе класса.