【问题标题】:How do I determine which URLLoader failed programmatically?如何确定哪个 URLLoader 以编程方式失败?
【发布时间】:2011-01-06 21:21:05
【问题描述】:

我正在开发一个使用 URLLoader 从远程服务器获取信息的 Flash 应用程序。我有一个函数可以根据产品 ID 创建信息请求。出现错误时,我想回退到备用 URL,但要创建备用 URL,我需要知道产品 ID。确定哪个 URLLoader 失败(以及哪个产品请求失败)以便我可以重新生成新 URL 的最佳方法是什么?

我的功能如下:

function loadData(productID:String):URLLoader {
  var productURL:URLRequest = new URLRequest("/path/to/product/" + productID);
  var dataLoader:URLLoader = new URLLoader();

  dataLoader.addEventListener(Event.COMPLETE, parseData);
  dataLoader.addEventListener(IOErrorEvent.IO_ERROR, handleDataError);
  dataLoader.load(productURL);

  return dataLoader;
}

function handleDataError(e:IOErrorEvent) {
  var productID:String = ???;
  var altProductURL:URLRequest = new URLRequest("/alternate/path/to/product/" + productID);
  var dataLoader:URLLoader = new URLLoader();

  dataLoader.load(altProductURL);
}

【问题讨论】:

    标签: flash actionscript-3 error-handling


    【解决方案1】:

    如果我错了,请纠正我,但 e.targete.currentTarget 失败的 URLLoader 吗?

    【讨论】:

    • 是的。在您的 handleDataError 函数中,“e.currentTarget”将评估为加载程序实例。从那里,您的一个选择就是访问您使用的 url 并对 ID 进行逆向工程?
    • 是的,e.target 和 e.currentTarget 获取了失败的 URLLoader,但它没有 url 属性可以为我提供任何信息来确定它是哪个 URLLoader。我正在寻找将 URLLoader 对象与其他数据(即产品 ID)交叉引用的最佳方法。换句话说,我如何将 URLLoader 对象绑定到 productID,以便从未命名的 URLLoader 对象中获取 productID?
    • @Myk:在这种情况下,URLLoader 没有 url 属性(除非我在某处有错误)。
    • 您要求提供URLLoader,而我没有想到URLRequest 是存储url 的地方。
    【解决方案2】:

    您可以将错误处理程序包装在一个局部变量中(描述一个新函数),这样您就可以将 ID 传递给接收错误事件的方法:

    function loadData(productID:String):URLLoader {
      var productURL:URLRequest = new URLRequest("/path/to/product/" + productID);
      var dataLoader:URLLoader = new URLLoader();
    
      var errHandler:Function = function(event:IOErrorEvent):void {
        handleDataError(event, productID);
      };
    
      dataLoader.addEventListener(Event.COMPLETE, parseData);
      dataLoader.addEventListener(IOErrorEvent.IO_ERROR, errHandler);
      dataLoader.load(productURL);
    
      return dataLoader;
    }
    
    function handleDataError(e:IOErrorEvent, productID:String) {
      var altProductURL:URLRequest = new URLRequest("/alternate/path/to/product/" + productID);
      var dataLoader:URLLoader = new URLLoader();
    
      dataLoader.load(altProductURL);
    }
    

    【讨论】:

    • 之所以选择这个,是因为它非常简单,并且可以用最少的代码优雅地回答问题。如果我需要长期使用它,或者如果我要在多个地方使用它(例如跨不同的项目),我可能会使用 Juan 的解决方案。
    • @Steropes,很高兴它成功了。不过我同意 - Juan 的解决方案非常优雅,并且很好地隐藏了故障转移功能。
    【解决方案3】:

    将错误处理程序包装在闭包中或从目标检索 id 的替代方法是编写一个隐藏重试机制的自定义加载器,因此您可以像使用普通加载器一样使用它。

    类似这样的东西(我只是在记事本中写的,所以它可能有错误,但只是为了给你一个想法......):

    public class ProductDataLoader extends EventDispatcher {
    
        private var _paths:Array;
        private var _id:String;
        private var _state:int; 
    
        private var _loader:URLLoader;
        private var _data:Object;
    
        public function get data():Object {
            return _data;
        }
    
        public function ProductDataLoader(id:String) {
            _paths = [
                "/path/to/product/",
                "/alternate/path/to/product/"
            ];
            _id = id;
            _state = -1;
    
            _loader = new URLLoader();
            _loader.addEventListener(Event.COMPLETE, handleComplete);
            _loader.addEventListener(IOErrorEvent.IO_ERROR, handleError);   
    
        }
    
        public function load():void {
            if(hasNextPath()) {
                _loader.load(new URLRequest(getNextPath()));
            } else {
                //  here, we ran out of paths to try
                //  you shouldn't get here unless you call loadProduct() 
                        //      more than once. 
                //  you should probably throw an error here, but that's up to
            }
    
        }
    
        private function hasNextPath():Boolean {
            return _state < _paths.length - 1;
        }
    
        private function getNextPath():String {
            _state++;
            return _paths[_state] + _id;    
        }
    
        private function handleComplete(e:Event):void {
            // redispatch the complete event
            _data = _loader.data;
            dispatchEvent(e);
        }
    
        private function handleError(e:Event):void {
            if(hasNextPath()) {
                loadProduct();
            } else {
                //  we tried all paths without success
                //  so we just redispatch the error event
                dispatchEvent(e);
            }   
        }
    
    }
    

    然后在你的加载函数中:

    function loadData(productID:String):URLLoader {
    
        var productLoader:ProductDataLoader = new ProductDataLoader(productId);
        dataLoader.addEventListener(Event.COMPLETE, parseData);
        dataLoader.addEventListener(IOErrorEvent.IO_ERROR, handleDataError);
        dataLoader.load();
    }
    

    【讨论】:

    • @bedwyr。谢谢。我喜欢这种方法的地方在于它对调用者隐藏了机制,因此调用代码保持简单。此外,如果您想添加一些更强大的错误处理(例如确保您的加载程序保持一致状态,在加载时不会重新输入等),您可以轻松地做到这一点,而不会弄乱“客户端”代码,这几乎可以将此加载器视为常规加载器。
    • 虽然比bedwyr 的代码更复杂,但这个解决方案更健壮,可以让我的应用程序面向未来,并在需要时轻松地让我重用代码。我选择了bedwyr的解决方案而不是这个,只是因为我需要一个只能使用一次的简单解决方案,并且我选择代码易读性而不是健壮性。
    猜你喜欢
    • 2010-09-08
    • 2017-03-24
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多