AngularJS : 如何在这种情况下使用$q promise 特性来等待数据就绪?

AngularJS : How to use the $q promise feature in this situation to wait for data to be ready?

我有一个 Controller,它在 Factory 中启动一个 API 调用。目前我开始通话,然后我在通话后有一个功能来检查 Array 的状态。但是我不确定如何在收集数据时强制它在这里等待,因此需要某种 $q 实现。

如您在下面的屏幕截图中所见,vs.tickers return 是一个空对象或数组。最后 GetTickersFactory 中的 console.log 触发:

第一个控制器

if (root.tickerType === 'portfolio') {

    // Call to factory to start the API GETS:
    GetTickersFactory.getTickers('portfolio');

    // I then call a function in the Factory to return the array
    // Which isn't ready yet of course since it returns undefined...
    vs.tickers = GetTickersFactory.returnPortfolioTickers();

    console.log('portfolio');
    console.log('vs.tickers = ', vs.tickers);
}

GetTickersFactory 中的 getTickers 函数 | 也许这有帮助:the Gist for the full Factory.

function getTickers(type, load, searchedTicker) {
    load = load || loadString; searchedTicker = searchedTicker || '';

    var portfolioTickersArray = [], searchedTickersArray  = [];

    tickersPane.loadingTickersDone = false;

    switch(type) {
        case 'searched':
            ....
            break;

        case 'portfolio':

            if (portfolioCached) {
                // The API Call (cached)
                ApiFactory.getWatchList().then(function(data) {
                    portfolioTickersArray = renderTickers(data.data.tickers, undefined, type);
                    portfolioTickers.that = portfolioTickersArray;
                    tickersPane.loadingTickersDone = true;
                    console.log('portfolioTickersArray: ', portfolioTickersArray);
                    return portfolioTickersArray;
                });

            } else {
                // The API Call (not cached)
                ApiFactory.getWatchListRefresh().then(function(data) {
                    portfolioTickersArray = renderTickers(data.data.tickers, undefined, type);
                    portfolioTickers.that = portfolioTickersArray;
                    portfolioCached = true;
                    tickersPane.loadingTickersDone = true;
                    console.log('portfolioTickersArray: ', portfolioTickersArray);
                    return portfolioTickersArray;
                });
            }
            break;
    }

    function renderTickers(data, searchedTicker, type) {
        ....
    }
}

我在 getTickersFactory.js 内部使用的 return 数组函数我相信我不应该使用它,而是弄清楚如何使用承诺:

function returnPortfolioTickers() {
    return portfolioTickers.that;
}

请注意,我最初确实尝试过此操作,但结果相同:

vs.tickers = GetTickersFactory.getTickers('portfolio');

vs.tickers 会 return undefined

如果你想使用 ES6 风格的 promise:

function getTickers(type, load, searchedTicker) {

  return $q(function (resolve, reject) {

     if (doTheGoodThings()) {
       resolve('This is ok!');
     } else {
       reject('This did not work');
     }

  }
}

然后在你的控制器中:

if (root.tickerType === 'portfolio') {

  GetTickersFactory.getTickers('portfolio').then(function (result) {
    console.log('Worked: ' + result);
  }, function (error) {
    console.log('Error: ' + error);
  });

}

你的 switch cases 应该 return 一个 promise,这样当 promise 得到解决时,它的调用函数将 .then 调用

工厂代码

function getTickers(type, load, searchedTicker) {
    //other code remains same
    tickersPane.loadingTickersDone = false;
    switch (type) {
        case 'searched':
            return ApiFactory.getTickers(null, load).then(function(data) {
                //other code remains same
                if (tickersPane.tempTickers.length > 0) {
                    //other code remains same
                    return returnData(searchedTickersArray);
                }
                return []; //return default variable to continue promise chain
            });
            break;
        case 'portfolio':
            tickersPane.addOption = false;
            tickersPane.removeOption = true;
            tickersPane.displayTopTags = false;
            tickersPane.displayPortfolio = true;

            if (portfolioCached) {
                return ApiFactory.getWatchList().then(function(data) {
                    //other code remains same
                    return returnData(portfolioTickersArray);
                });
            } else {
                return ApiFactory.getWatchListRefresh().then(function(data) {
                    //other code remains same
                    return returnData(portfolioTickersArray);
                });
            }
            break;
    }
    function renderTickers(data, searchedTicker, type) {
        //this should be as is
    }
    function returnData(data) {
        tickersPane.loadingTickersDone = true;
        return data;
    }
    //tickersPane.loadingTickersDone = true;
    //return data; //removed this line and move to function
}

控制器

if (root.tickerType === 'portfolio') {
    // Call to factory to start the API GETS:
    GetTickersFactory.getTickers('portfolio').then(resp){
         vs.tickers = GetTickersFactory.returnPortfolioTickers();
         console.log('portfolio');
         console.log('vs.tickers = ', vs.tickers);
    };
}

您已经有两个 return 承诺的方法(getWatchList 和 getWatchListRefresh),因此您可以 return 这些方法并链接更多 .then。这里不用$q。

希望这个简化的示例可以帮助您朝着正确的方向前进...

function getTickers(type) {
    var tickers;

    switch(type) {
        // ...
        case 'portfolio': 
            var getList = portfolioCached ? getWatchList : getWatchListRefresh;
            // tickers will be set to the promise returned
            // by getWatchList or getWatchListRefresh
            tickers = getList().then(function(data) {
                if (!portfolioCached) {
                  portfolioCached = true;
                }
                // the result returned by renderTickers will be 
                // passed to any `.then` that is chained
                return renderTickers(data.data.tickers, undefined, type);
            });
        break;
    }

    // return the tickers promise
    return tickers;
}

然后在你的控制器中:

// the `tickers` param here will be the result
// returned by renderTickers()
GetTickersFactory.getTickers('portfolio').then(function(tickers) {
    vs.tickers = tickers;
});