JavaScript обещание. Потом внутри. Потом не работает - PullRequest
0 голосов
/ 06 апреля 2020

Текущее состояние:

У меня есть следующая функция в компоновщике ссылок, который использует сервис конфигурации, который возвращает обещание с некоторыми параметрами среды:

_createLink: function (label, args) {
   return LinkBuilder.builder()
      .withLabel(label)
      .withUrl(ConfigService.getConfig()
         .then((env) => env.baseUrl 
                      + TranslationService.instant('MY.URL', args)))
      .buildLink();
},

Несколько объяснений:

  • withUrl(...) выполняет следующие действия:

    withUrl: function (param) {
                        if (typeof param === 'string') {
                            builder.value.linkUrl = param;
                        } else if (typeof param === 'function') {
                            builder.value.linkCalculationFunction = param;
                        } else if (typeof param === 'object' && typeof param.lazyBuildUrl === 'function') {
                            builder.value.linkCalculationFunction = param.lazyBuildUrl();
                        } else if (typeof param === 'object' && typeof param.then === 'function') {
                            builder.value.linkCalculationFunction = () => param;
                        } else {
                            throw new Error('invalid url param ' + param);
                        }
                        return builder;
                    },

  • withLabel(label) установит метку, которая будет отображаться в виде текста URL

withLabel: function (label) {builder.value.labelKey = label; return builder;}

  • .buildLink() просто возвращает builder.value, с URL и всеми другими параметрами:

buildLink: function () {return builder.value;}

  • TranslationService найдет запись 'MY.URL' в файле JSON с переводами. Значение будет что-то вроде 'http://www.myserver.com#name={{name}}&age={{age}}'. Там будут вставлены параметры name и age из args.

Проблема:

Мне нужно кодировать эти args с использованием внешнего сервиса, который также возвращает обещание, а затем добавить возвращаемое значение к моей ссылке. Этот внешний сервис вернет что-то вроде 'data': {'encodedId': '123-456-789'}, и моя последняя ссылка должна быть: http://www.myserver.com#encodedId=123-456-789. Вот что я сделал:

Моя первоначальная попытка:

В файле JSON с переводами я удалил параметры из записи, так что теперь это только: 'http://www.myserver.com#'

Функция _createLink теперь выглядит следующим образом:

_createLink: function (label, args) {
   let content = {
      'name': args.name,
      'age': args.age
   };
   return EncodingService.saveContent(content)
       .then((data) => {
           return LinkBuilder.builder()
              .withLabel(label)
              .withUrl(ConfigService.getConfig()
                  .then((env) => env.baseUrl 
                               + TranslationService.instant('MY.URL') 
                               + 'encodedId=' + data.encodedId))
              .buildLink();
},

Когда я ставлю точку останова на последней строке then, я вижу, что у меня есть правильный data.encodedId, правильный env.baseUrl и TranslationService также правильно возвращает запись JSON. Но по какой-то причине я больше не вижу ссылки на своей странице. Я предполагаю, что я делаю что-то не так с цепочкой .then s, но я не уверен, что.

Еще одна попытка, которая все еще не работает:

Вот третья версия, которая все еще не работает:

_createLink: function (label, args) {
       let content = {
          'name': args.name,
          'age': args.age
       };
       return $q.all([
          EncodingService.saveContent(content),
          ConfigService.getConfig()
       ])
           .then((data) => {
               let url = data[1].baseUrl
                       + TranslationService.instant('MY.URL') 
                       + 'encodedId=' + data[0].encodedId;
               return LinkBuilder.builder()
                  .withLabel(label)
                  .withUrl(url)
                  .buildLink();
    },

Опять же, я установил точку останова в последнем операторе return, и там у меня правильно сформировано url ...

Использование `_createLink`:

Эта функция используется следующим образом:

getLeadLink: function (label, access, address) {
   return myService._createLink(label, someService._createArguments(access, address));
        },

... и getLeadLink используется в таком компоненте, как этот:

this.$onInit = () => {
...
   this.leadLink = OtherService.getLeadLink('LINEINFO.LEAD.LINK', someData.access, someData.address);
...
};

... и leadLink затем отображаются в файле HTML.

Примечание. Ни одна из этих вещей не была изменена, поэтому использование _createLink и отображение ссылки по-прежнему так же, как это было раньше.

1 Ответ

2 голосов
/ 06 апреля 2020

Третья попытка идет в правильном направлении.

Однако вы не можете получить future URL now . И поэтому любая попытка, которая в конце концов ожидает простого вызова функции для возврата URL, не может быть правильной. Такая функция (например, _createLink) считается возвращаемой до выполнения асинхронных частей (т.е. любых обратных вызовов then). В вашей третьей попытке вы улучшили ситуацию, так что по крайней мере _createLink вернет обещание .

Теперь осталось дождаться разрешения этого обещания.

Итак, любой выполнение функции обтекания _createLink должно учитывать асинхронный шаблон:

getLeadLink: function (label, access, address) {
   return myService._createLink(label, someService._createArguments(access, address));
},

Это нормально, но следует понимать, что _createLink возвращает не URL, а обещание. И так же getLeadLink вернет обещание.

Вы пишете, что хотите отобразить URL, чтобы вы делали что-то вроде этого (я не знаю, как вы будете отображать, так что это упрощено) :

OtherService.getLeadLink('LINEINFO.LEAD.LINK', someData.access, someData.address).then(function(builder) {
    var $link = $("<a>").attr("href", builder.value.linkUrl)
                        .text(builder.value.labelKey);
    $(document).append($link);
});

Ключевое сообщение: не пытайтесь получить URL-адрес в качестве возвращаемого значения функции. Неважно, сколько оберток вы пишете вокруг основной логики; она останется асинхронной задачей, поэтому вам также нужно асинхронно получать и отображать URL. Вам нужно будет сделать это с помощью then обратного вызова или использовать синтаксис await, что делает все, что следует за ним, асинхронным кодом.

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