【问题标题】:Running an async method in a syncronized manner以同步方式运行异步方法
【发布时间】:2014-05-04 17:25:06
【问题描述】:

我有一个简单的for循环,它基本上检查图像是否存储在文件系统中,如果没有,则下载并渲染UI:

for (var t = 0; t < toJSON.length; t++) {
    if (t < 3) {
        var view = Titanium.UI.createImageView({
            width: 320,
            height: 310,
            //top: 10 
        });
        image_url = toJSON[t];
        //start
        if (utilities.CheckIfImageExist(utilities.ExtractImageName(image_url))) {
            var parent = Titanium.Filesystem.getApplicationDataDirectory();
            var picture = Titanium.Filesystem.getFile(parent, 'pictures');
            var picturePath = parent + 'pictures/';
            Ti.API.info('picturePath: ' + picturePath);
            var f = Titanium.Filesystem.getFile(picturePath, utilities.ExtractImageName(image_url));
            var blob = f.read();
            // here is saved blog file
            console.log('Image already downloaded');
            var width = blob.width;
            var height = blob.height;
            //crop  so it fits in image view
            if (width > height) {
                view.image = ImageFactory.imageAsCropped(blob, {
                    width: height,
                    height: height,
                    x: 60,
                    y: 0
                });
            } else {
                view.image = ImageFactory.imageAsCropped(blob, {
                    width: (width - 1),
                    height: (width - 1),
                    x: 60,
                    y: 0
                });
            }
        } else {
            //do new loop - async causing problems
            alert('not downloaded');
            // if image is not downloaded we will download it here
            utilities.APIGetRequestImage(image_url, function (e) {
                alert('begin downloaded');
                var status = this.status;
                if (status == 200) {
                    Ti.API.info(this.responseData);
                    //save to directory
                    utilities.SaveImageToDirectory(this.responseData, image_url);
                    //create view
                    var view = Titanium.UI.createImageView({
                        width: 320,
                        height: 310,
                        //top: 10
                    });
                    var width = this.responseData.width;
                    var height = this.responseData.height;
                    //crop  so it fits in image view
                    if (width > height) {
                        var view = Titanium.UI.createImageView({
                            width: 320,
                            height: 310,
                            //top: 10
                        });
                        view.image = ImageFactory.imageAsCropped(this.responseData, {
                            width: height,
                            height: height,
                            x: 60,
                            y: 0
                        });
                        //  $.scrollableView.addView(view);
                        viewArr.push(view);
                    } else {
                        view.image = ImageFactory.imageAsCropped(this.responseData, {
                            width: (width - 1),
                            height: (width - 1),
                            x: 60,
                            y: 0
                        });
                        viewArr.push(view);
                        //when t = 3, all views are put inside array, set image view
                        //if(t==3){
                        //}
                    }
                }
            }, function (err) {
                alert('error downloading image');
            });
        }
    }
}

“开始下载”的代码仅在 for 循环执行 IF 语句的前半部分(其中显示“未下载”)之后执行,到 t=3。

for 循环然后执行 else 语句,我遇到的麻烦是我需要它以同步方式执行它,因为我依赖 t 值来知道要下载哪个图像并将其放置在视图中。

    utilities.APIGetRequestImage(image_url, function(e) {

是从服务器获取文件并下载的回调方法。

如何让这两种方法同时运行?

【问题讨论】:

  • 你有什么问题?
  • image_url,如果第一次if语句检查失败,每次迭代都应该传入if语句的最后部分。我怀疑由于最后一部分是异步函数,它没有正确迭代
  • geekabyte.blogspot.co.uk/2013/04/… 这是另一个例子 - callblacks in loop
  • 那不应该是“开始下载”,而是“结束下载,开始保存”?

标签: javascript for-loop asynchronous


【解决方案1】:

检查一下:

for (var t = 0; t < toJSON.length; t++) {
    if (t < 3) {
        var view = Titanium.UI.createImageView({
            width: 320,
            height: 310,
            //top: 10 
        });
        image_url = toJSON[t];
        //start
        if (utilities.CheckIfImageExist(utilities.ExtractImageName(image_url))) {
            var parent = Titanium.Filesystem.getApplicationDataDirectory();
            var picture = Titanium.Filesystem.getFile(parent, 'pictures');
            var picturePath = parent + 'pictures/';
            Ti.API.info('picturePath: ' + picturePath);
            var f = Titanium.Filesystem.getFile(picturePath, utilities.ExtractImageName(image_url));
            var blob = f.read();
            // here is saved blog file
            console.log('Image already downloaded');
            var width = blob.width;
            var height = blob.height;
            //crop  so it fits in image view
            if (width > height) {
                view.image = ImageFactory.imageAsCropped(blob, {
                    width: height,
                    height: height,
                    x: 60,
                    y: 0
                });
            } else {
                view.image = ImageFactory.imageAsCropped(blob, {
                    width: (width - 1),
                    height: (width - 1),
                    x: 60,
                    y: 0
                });
            }
        } else {
            //do new loop - async causing problems
            alert('not downloaded');
            // if image is not downloaded we will download it here
            utilities.APIGetRequestImage(image_url, (function (t, image_url) {
                return function (e) {                               // <----- wrap callback function
                    alert('begin downloaded');
                    var status = this.status;
                    if (status == 200) {
                        Ti.API.info(this.responseData);
                        //save to directory
                        utilities.SaveImageToDirectory(this.responseData, image_url);
                        //create view
                        var view = Titanium.UI.createImageView({
                            width: 320,
                            height: 310,
                            //top: 10
                        });
                        var width = this.responseData.width;
                        var height = this.responseData.height;
                        //crop  so it fits in image view
                        if (width > height) {
                            var view = Titanium.UI.createImageView({
                                width: 320,
                                height: 310,
                                //top: 10
                            });
                            view.image = ImageFactory.imageAsCropped(this.responseData, {
                                width: height,
                                height: height,
                                x: 60,
                                y: 0
                            });
                            //  $.scrollableView.addView(view);
                            viewArr.push(view);
                        } else {
                            view.image = ImageFactory.imageAsCropped(this.responseData, {
                                width: (width - 1),
                                height: (width - 1),
                                x: 60,
                                y: 0
                            });
                            viewArr.push(view);
                            //when t = 3, all views are put inside array, set image view
                            //if(t==3){
                            //}
                        }
                    }
                };
            })(t, image_url), function (err) {
                alert('error downloading image');
            });
        }
    }
}

通过包装utilities.APIGetRequestImage 回调,timage_url 被正确传递。

【讨论】:

  • Watchme,成功了。这里到底发生了什么?为什么这行得通?非常感谢
  • 包装函数(闭包)被同步调用。回调函数使用闭包的内部作用域,当外部作用域发生变化时,它不会改变。阅读更多关于闭包的信息:stackoverflow.com/questions/111102/…
  • 顺便说一句,我添加了一个警报来检查异步函数中的 t 值,它似乎按照 1,0,2 这个顺序进行,而不是 0,1,2 - 不是确定为什么会这样
  • 多次测试,结果可能会有所不同。这是因为utilities.APIGetRequestImage 的执行并不总是需要相同的时间。出于某种原因,第二次通话在第一次通话之前结束。
  • 无论如何我可以通过编程方式防止这种情况发生吗?还是硬编码说 3 个 div(3 个图像视图)并根据 t 值确保正确的图像进入正确的视图会更好吗?
【解决方案2】:

当你说“需要它以同步方式完成它”时,你实际上并不需要。你说你想“让两个方法同时运行”,这需要异步。

只需交换检查 if(t==3) (始终为 3,即使您确实像 @wachme 建议的那样在其周围放置了一个闭包,那么对于最后开始的下载,它也只是 3 -不是最后一个结束的)检查您收到的物品数量:if(viewArr.length==3)。当所有三个回调都执行时,它将是3,您可以继续执行您的任务。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-19
    • 2023-03-19
    • 1970-01-01
    • 2019-05-26
    • 1970-01-01
    相关资源
    最近更新 更多