【问题标题】:call function synchronously inside an angular for each在每个角度内同步调用函数
【发布时间】:2017-05-17 01:13:42
【问题描述】:

我在 ionic 项目中使用 ngCordova 文件传输插件从 url 下载一组图像。这是我正在使用的代码。

// Save a image file in a given directory
$scope.saveImage = function(dir,imgUrl,imageName) {

    var url = imgUrl;
    var targetPath = cordova.file.dataDirectory+ dir+"/" + imageName;
    var trustHosts = true;
    var options = {};

    // Download the image using cordovafiletransfer plugin
    $cordovaFileTransfer.download(url, targetPath, options, trustHosts)
    .then(function(result) {
        $scope.loadedCount ++;
        $ionicLoading.show({template : "<ion-spinner class='spinner-energized'></ion-spinner><p> Downloading pages : "+ $scope.loadedCount+" of "+ $scope.pages.length+ "</p><p>Please wait...</p><p><button class=\"button button-block button-positive\">continue in background</button></p>"});
        if($scope.loadedCount == $scope.pages.length) {
            $ionicLoading.hide();
            $scope.showDownloadSuccessAlert = function() {
                var alertPopup = $ionicPopup.alert({
                    title: 'Success!',
                    template: "Your magazine successfully downloaded. You can view it on Downloads!"
                });
            };
            $scope.showDownloadSuccessAlert();
        }
    }, function(err) {
        alert(JSON.stringify(err));
    }, function (progress) {
        if($scope.loadedCount > 80) {
        }
    });
};

// Download the current magazine
$scope.downloadMagazine = function() {
    if($rootScope.user.user_id == undefined) {
        $scope.showLoginAlert = function() {
                var alertPopup = $ionicPopup.alert({
                    title: 'Oops!',
                    template: "Your must login to download magazines"
                });
            };
        $scope.showLoginAlert();
        return;
    }

    document.addEventListener('deviceready', function () {

        var dirName = $rootScope.currentIssue.slug+'_VOL_'+$rootScope.currentIssue.vol+'_ISU_'+$rootScope.currentIssue.issue;

        // First create the directory
         $cordovaFile.createDir(cordova.file.dataDirectory, dirName, false)
        .then(function (success) {
            var count = 1;
            $scope.loadedCount = 0;
            angular.forEach($scope.pages, function(value, key) {
               var imgName = count+".png";
               $scope.saveImage(dirName,value.link,imgName); // Then save images one by one to the created directory.
               count++;
            });

        }, function (error) {
            // Directory already exists means that the magazine is already downloaded.
            $scope.showDownloadedAlert = function() {
                var alertPopup = $ionicPopup.alert({
                    title: 'Why worry!',
                    template: "Your have already downloaded this magazine. You can view it on downloads"
                });
            };
            $scope.showDownloadedAlert();
        });

    }, false);
};

})

这里的问题是程序尝试一次下载所有内容,而无需等待前一个完成。如何等待一个文件完成下载然后再启动另一个文件?

谢谢

【问题讨论】:

    标签: angularjs ionic-framework synchronization cordova-plugins ngcordova


    【解决方案1】:

    如果您想自动执行此操作(您不是第一个:How can I execute array of promises in sequential order?),您可以尝试将地址列表减少到一个可以完成整个链的 Promise。

    $scope.pages.reduce(function (curr,next) {
          return curr.then(function(){            
                return $scope.saveImage(dirName, curr.link, imgName);
          });
      }, Promise.resolve()).then(function(result) {
    
            $ionicLoading.show({template : "<ion-spinner class='spinner-energized'></ion-spinner><p> Downloading pages : "+ $scope.loadedCount+" of "+ $scope.pages.length+ "</p><p>Please wait...</p><p><button class=\"button button-block button-positive\">continue in background</button></p>"});
            if($scope.loadedCount == $scope.pages.length) {
                $ionicLoading.hide();
                $scope.showDownloadSuccessAlert = function() {
                    var alertPopup = $ionicPopup.alert({
                    title: 'Success!',
                    template: "Your magazine successfully downloaded. You can view it on Downloads!"
                });
            };
            $scope.showDownloadSuccessAlert();
        }
      });
    

    别忘了让你的 saveImage 异步返回 promise

    更新:

    您需要从保存方法中删除 then 逻辑并返回 download 方法调用:

    return $cordovaFileTransfer.download(url, targetPath, options, trustHosts).promise;
    

    然后您可以将您的下载处理程序放入Promise.resolve()).then。见上文。

    【讨论】:

    • 您能否解释一下“使您的saveImage 异步返回promise。对不起,我是新手。
    • 这给出了错误,在reduce函数内部,变量curr似乎是一个空对象!
    【解决方案2】:

    除了链接你的承诺之外别无他法。这是一个例子:

    angular.module('app', [])
      .service('fakeDownloadService', function($timeout) {
        this.download = (file) => $timeout(() => file, 100);
        return this;
      })
      .run(function($rootScope, $q, fakeDownloadService) {
        var listOfFiles = [];
        for (var i = 0; i < 10; i++)
          listOfFiles.push('file' + i);
        $rootScope.log = [];
        $rootScope.download = () => {
          listOfFiles
            .reduce((prev, curr) => {
              return prev.then((result) => {
                if(result)
                $rootScope.log.push(result + ' downloaded');
                return fakeDownloadService.download(curr);
              });
            }, $q.resolve())
            .then(() => $rootScope.log.push('all done'));
        };
      });
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.9/angular.min.js"></script>
    <div ng-app="app">
      <button ng-click="download()">Start</button>
      <div>Log:</div>
      <ul>
        <li ng-repeat="entry in log track by $index">
          {{entry}}
        </li>
      </ul>
    </div>

    【讨论】:

      猜你喜欢
      • 2013-07-21
      • 1970-01-01
      • 1970-01-01
      • 2012-07-25
      • 2020-01-27
      • 2014-03-30
      • 2020-11-13
      • 2020-09-29
      • 1970-01-01
      相关资源
      最近更新 更多