2016-05-13 3 views
2

У меня есть следующая функция, моя цель - нажать на список элементов, когда компоненты могут идентифицировать их родительский элемент. Проблема, которая у меня есть, заключается в том, что когда я нажимаю на список console.log() показывает мне, что объект находится там, но когда я возвращаю список и перехватываю его в другой функции, в списке ничего нет. Я думаю, что список предметов возвращается до того, как код над ним будет выполнен.Обещания с angularJS и машинописным текстом

private get_items_for_request() { 
    return this.Item.forRequest(this.request.id, ['group']) 
    .then((_items) => { 
     var items = []; 
     for (var item of _items) { 
     return this.ItemComponent.forItem(item.id, ['type']) 
      .then((_components) => { 
      for (var component of _components) { 
       if (component.type.can_identify_item) { 
       items.push({ 
        group_id: item.group.reference, 
        identifier_code: this.remove_check_digit_if_necessary(
         component.identifier_code), 
        quantity: 1 
       }); 
       break; 
       } 
      } 
      }, (reason) => { 
      this.Toast.error(
       this.gettextCatalog.getString('components.load_failed')); 
      return []; 
      }); 
     } 
     return items; 
    }, (reason) => { 
     this.Toast.error(
      this.gettextCatalog.getString('items.failed_load')); 
     return []; 
    }); 
} 

ответ

2

Я боюсь, что проблема связана с вашим подходом, а не с самим кодом. Обещание - это просто обещание данных в будущем. Таким образом, когда вы возвращаете функцию (сразу), обещание еще не разрешено, и данные, которые ваша функция вызова вызывающего абонента захватывает, по-прежнему пуст. Я не вижу console.log() в вашем коде, но подозреваю, что вы поместили его где-то внутри, а затем(), который будет вызываться после получения данных. Таким образом, вы увидите, что данные регистрируются. Проблема заключается в том, что к этому времени get_items_for_request() уже возвращен, и ваша функция вызывающего абонента уже перешла.

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

Для синхронной выборки отметьте this response. Но будьте осторожны, что синхронная выборка будет ухудшать отзывчивость вашего скрипта.

Для асинхронной выборки (с использованием обещаний) вам необходимо определить обратный вызов, как только все данные были извлечены. Я не буду пытаться исправить ваш код, но он должен идти по следующему эскизу в javascript. Хотя имейте в виду, это всего лишь эскиз.

function get_items_for_request(onSuccess) { 
    var items = [] 
    var total = -1 
    var sofar = 0; 
    this.Item.forRequest(this.request.id, ['group']) 
    .then(function (_items) { 
     var items = []; 
     total = _items.length // remember how many nested calls will be made 
     for (var item of _items) { 
     this.ItemComponent.forItem(item.id, ['type']) 
      .then(function (_components) { 
      // push received data to the items array here 
      sofar++ 
      if (sofar == total) { // all done 
       onSuccess(items) 
      } 
      } 
     } 
    } 
} 
0

В первом обратном вызове вы имеете два возврата, только первый работает. Вы возвращаете обещание после первого for, которое вы разрешите на undefined. Вам следует подождать массив обещаний, каждый из которых соответствует вызову this.ItemComponent.forItem.

Promise.all помогает с этим: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

Вы должны сделать что-то вроде этого:

return this.Item.forRequest(this.request.id, ['group']).then((_items) => { 
     return Promise.all(_items.map(function (item) { 
      return this.ItemComponent.forItem(item.id, ['type']).then((_components) => { 
       for (var component of _components) { 
        if (component.type.can_identify_item) { 
         return { 
          group_id: item.group.reference, 
          identifier_code: this.remove_check_digit_if_necessary(
           component.identifier_code), 
          quantity: 1 
         }; 
        } 
       } 
      }, (reason) => { 
       this.Toast.error(
        this.gettextCatalog.getString('components.load_failed')); 
       return []; 
      }); 
     })); 
    }, (reason) => { 
     this.Toast.error(
      this.gettextCatalog.getString('items.failed_load')); 
     return []; 
    }) 

Если вы хотите только один элемент, найти первый не falsy элемент результирующего массива

+0

@GiftZwergrapper, если вы хотите получить рабочий код, вам необходимо связать пример plunkr или, по крайней мере, весь файл. Я не уверен, что вы ожидали, мы не медиумы. Если вы используете Angular 1, '' q q - ваша библиотека Promise. –

+2

@GiftZwergrapper также, обратите внимание, что ошибка, о которой я указывал, все еще существует, вы немного агрессивны с downvotes здесь. –

+0

В угловом режиме вы можете использовать '$ q.all' для той же цели – Icycool

Смежные вопросы