Асинхронная функция в Getter с возвратом в обратном вызове

Я хочу определить свойство объекта только для чтения, которое асинхронно извлекает значение, а затем возвращает его с помощью новых геттеров EcmaScript 5.

Однако свойство всегда возвращает undefined, даже несмотря на то, что magicValue в приведенном ниже примере кода окончательно никогда не является неопределенным. Кроме того, когда я просто return 'xxx';, напечатанное значение по-прежнему равно undefined. Это работает только тогда, когда я return вне функции обратного вызова.

Кажется, что return выполняется немедленно, независимо от того, вызывается ли обратный вызов myAsyncFunction. Я не уверен, является ли это ошибкой в ​​V8 или я злоупотребляю геттерами JavaScript.
Могу ли я заставить это работать? Я подумал, что, поскольку теперь я могу использовать геттеры и сеттеры, я буду использовать геттеры/сеттеры для чтения и записи свойств и обычных функций для выполнения определенных задач.

var User = function (id) {
    this.id = id;
};

Object.defineProperty(User.prototype, 'magic', {
    get : function () {
        myAsyncFunction(function (magicValue) {
            return magicValue;
        });
    }
});

var u = new User(5);
console.log(u.magic);

Печатает undefined.


person Max Kueng    schedule 07.08.2012    source источник
comment
Вы не можете вернуть результат из асинхронной функции в синхронную операцию — это нелогичная конструкция. Более того, ваш myAsyncFunction никогда не вызывается — он просто объявляется. Какова природа вашей асинхронной операции?   -  person Mitya    schedule 07.08.2012
comment
Приведенный выше код является просто примером. Настоящая цель состоит в том, что у User есть свойство, называемое account. При доступе к свойству учетной записи, когда у пользователя еще нет учетной записи, она будет сначала создана, а затем будет возвращена.   -  person Max Kueng    schedule 07.08.2012
comment
Через АЯКС? Но геттер — это синхронная операция. Вы не можете вернуть что-то из асинхронного геттера - вам понадобится другой шаблон.   -  person Mitya    schedule 07.08.2012
comment
Не через Ajax, а через файловую систему. Ясно, я думал, что геттеру понадобится еще пара микросекунд, пока он не вернется.   -  person Max Kueng    schedule 07.08.2012
comment
Нет, геттер является синхронным, поэтому вернется (или нет) немедленно.   -  person Mitya    schedule 07.08.2012
comment
Как вы думаете, если я синхронизирую (используя синхронные функции файловой системы) функцию создания учетной записи, все будет в порядке? До возвращения может пройти столько же времени.   -  person Max Kueng    schedule 07.08.2012
comment
Да, если вы делаете операцию синхронной, это вариант, но тогда вы блокируете свой скрипт. Если это вообще возможно, я лично попытался бы найти другой образец.   -  person Mitya    schedule 07.08.2012
comment
Хорошо, я думаю, вы правы. И то, что вы говорите, имеет смысл. Думаю, вместо этого я просто использую обычную функцию. Спасибо за вашу помощь :)   -  person Max Kueng    schedule 07.08.2012


Ответы (3)


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

Object.defineProperty(User.prototype, "magic", {
  get: function() {
    return new Promise(function(resolve, reject) {
      setTimeout(function() {
        resolve(JSON.stringify({
          magic: 'value'
        }));
      }, 1000);
    });
  }
});

Вот рабочий пример: https://jsfiddle.net/tw6gaudz/2/

person Roustalski    schedule 27.01.2016
comment
Есть ли способ избежать промисов и использовать async и await? - person adelriosantiago; 26.02.2019
comment
@adelriosantiago: Async/Await использует обещания внизу. Вы можете использовать асинхронную функцию и ждать геттера. Вот модифицированная версия с использованием async/await: jsfiddle.net/z6hdbfwu - person Andrew Pearson; 13.04.2019

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

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

person Max Kueng    schedule 07.08.2012

Вы можете использовать «сеттер»:

var User = function (id) {
    this.id = id;
};

Object.defineProperty(User.prototype, 'magic', {
    set : function (value) {
        setTimeout(value.bind(0, "hello"), 1000);
        return true;
    }
});

var a = new User(5);

a.magic = function(msg){
    alert(msg);
};
person Esailija    schedule 07.08.2012