最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 使用装饰器模式强大你的 fetch

    正文概述 掘金(公众号_前端修罗场)   2021-05-03   574

    使用装饰器模式强大你的 fetch

    1. fetch() 很好,但你可能希望更好

    fetch() API允许你在web应用程序中执行网络请求。

    fetch()的用法非常简单:调用fetch ('/movies.json')来启动请求。当请求完成时,您将获得一个Response对象,从中提取数据。

    下面是一个简单的例子,如何从movies.json URL获取JSON格式数据:

    async function executeRequest() {
      const response = await fetch('/movies.json');
      const moviesJson = await response.json();
      console.log(moviesJson);
    }
    
    executeRequest(); 
    // logs [{ name: 'Heat' }, { name: 'Alien' }]
    
    

    如上面的代码片段所示,必须手动从响应中提取JSON对象:moviesJson = await response.JSON()。只做一次,没问题。但是如果您的应用程序执行许多请求,那么使用await response.json()提取JSON对象的所有时间是非常繁琐的。

    因此,通常使用第三方库,比如axios,它可以极大地简化请求的处理。考虑使用axios获取相同的电影:

    async function executeRequest() {
      const moviesJson = await axios('/movies.json');
      console.log(moviesJson);
    }
    
    executeRequest(); 
    // logs [{ name: 'Heat' }, { name: 'Alien' }]
    

    moviesJson = await axios('/movies.json')返回实际的JSON响应。不必像fetch()所要求的那样手动提取JSON

    但是,使用像axios这样的辅助库也会带来一些问题

    首先,它增加了web应用程序的bundle大小。其次,您的应用程序与第三方库相结合:您获得了该库的所有好处,但也得到了它的所有bug

    我的目的是采用一种不同的方法,从这两个方面都得到了最好的结果——使用装饰器模式来增加fetch() API的易用性和灵活性

    其思想是将一个基fetch类(我将展示如何定义它)包装为您需要的任何其他功能:提取JSON、超时、在糟糕的HTTP状态下抛出错误、处理auth头,等等。让我们在下一节中看看如何做到这一点。

    2. 准备 Fetcher 接口

    装饰器模式非常有用,因为它支持以灵活和松散耦合的方式在基本逻辑之上添加功能(换句话说——装饰)。

    如果你不熟悉装饰模式,我建议您阅读它是如何工作的。

    应用装饰器来增强fetch()需要几个简单的步骤:

    • 第一步是声明一个名为Fetcher的抽象接口:
    type ResponseWithData = Response & { data?: any };
    
    interface Fetcher {
      run(
        input: RequestInfo, 
        init?: RequestInit
      ): Promise<ResponseWithData>;
    } 
    

    Fetcher接口只有一个方法,它接受相同的参数并返回与常规fetch()相同的数据类型。

    • 第二步是实现基本的fetcher类:
    class BasicFetcher implements Fetcher {
      run(
        input: RequestInfo, 
        init?: RequestInit
      ): Promise<ResponseWithData> {
        return fetch(input, init);
      }
    }
    

    BasicFetcher实现了Fetcher接口。它的一个方法run()调用常规的fetch()函数。

    例如,让我们使用基本的fetcher类来获取电影列表:

    const fetcher = new BasicFetcher();
    const decoratedFetch = fetcher.run.bind(fetcher);
    
    async function executeRequest() {
      const response = await decoratedFetch('/movies.json');
      const moviesJson = await response.json();
      console.log(moviesJson);
    }
    
    executeRequest(); 
    // logs [{ name: 'Heat' }, { name: 'Alien' }]
    

    const fetcher = new BasicFetcher()创建一个fetcher类的实例。decoratedFetch = fetcher.run.bind(fetcher)创建一个绑定方法。

    然后你可以使用decoratedFetch('/movies.JSON ')来获取电影JSON,就像使用常规的fetch()一样。

    在这一步,BasicFetcher类没有带来好处。此外,由于新接口和新类的出现,事情变得更加复杂!稍等片刻,你会发现当装饰者模式被引入到行动中时所带来的巨大好处。

    3. 给提取 JSON 数据的方法添加装饰器

    装饰器模式的主要是装饰器类。

    装饰器类必须符合Fetcher接口,包装被装饰的实例,以及在run()方法中引入额外的功能

    让我们实现一个从响应对象中提取JSON数据的装饰器:

    class JsonFetcherDecorator implements Fetcher {
      private decoratee: Fetcher;
    
      constructor (decoratee: Fetcher) {
        this.decoratee = decoratee;
      }
    
      async run(
        input: RequestInfo, 
        init?: RequestInit
      ): Promise<ResponseWithData> {
        const response = await this.decoratee.run(input, init);
        const json = await response.json();
        response.data = json;
        return response;
      }
    }
    

    让我们仔细看看JsonFetcherDecorator是如何构造的。

    JsonFetcherDecorator符合Fetcher接口。

    JsonExtractorFetch有一个私有字段decoratee,它也符合Fetcher接口。在run()方法中this.decoratee.run(input, init)执行实际的数据获取。

    然后json = await response.json()从响应中提取json数据。最后,响应。data = json将提取的json数据分配给响应对象。

    现在让我们用JsonFetcherDecorator装饰器来组合装饰BasicFetcher,并简化fetch()的使用:

    const fetcher = new JsonFetcherDecorator(
      new BasicFetcher()
    );
    const decoratedFetch = fetcher.run.bind(fetcher);
    
    async function executeRequest() {
      const { data } = await decoratedFetch('/movies.json');
      console.log(data);
    }
    
    executeRequest(); 
    // logs [{ name: 'Heat' }, { name: 'Alien' }]
    

    现在,您可以从响应对象的data属性访问所提取的数据,而不是从响应中手动提取JSON数据。

    通过将JSON提取器移动到装饰器,现在在任何使用const {data} = decoratedFetch(URL)的地方,你都不必手动提取JSON对象。

    4. 创建请求超时装饰器

    默认情况下,fetch() API会在浏览器指定的时间超时。在Chrome中,网络请求超时时间为300秒,而在Firefox中超时时间为90秒。

    用户可以等待8秒来完成简单的请求。这就是为什么需要为网络请求设置一个超时,并在8秒后通知用户网络问题的原因。

    装饰器模式的伟大之处在于,可以使用任意多的装饰器装饰你的基本实现!那么,让我们为取回请求创建一个超时装饰器:

    const TIMEOUT = 8000; // 8 seconds
    
    class TimeoutFetcherDecorator implements Fetcher {
      private decoratee: Fetcher;
    
      constructor(decoratee: Fetcher) {
        this.decoratee = decoratee;
      }
    
      async run(
        input: RequestInfo, 
        init?: RequestInit
      ): Promise<ResponseWithData> {
        const controller = new AbortController();
        const id = setTimeout(() => controller.abort(), TIMEOUT);
        const response = await this.decoratee.run(input, {
          ...init,
          signal: controller.signal
        });
        clearTimeout(id);
        return response;
      }
    }
    

    TimeoutFetcherDecorator是一个实现Fetcher接口的decorator

    TimeoutFetcherDecoratorrun()方法内部:如果请求在8秒内没有完成,则使用中止控制器中止请求。

    现在让我们来使用这个装饰器:

    const fetcher = new TimeoutFetcherDecorator(
      new JsonFetcherDecorator(
        new BasicFetcher()
      )
    );
    const decoratedFetch = fetcher.run.bind(fetcher);
    
    async function executeRequest() {
      try {
        const { data } = await decoratedFetch('/movies.json');
        console.log(data);
      } catch (error) {
        // Timeouts if the request takes
        // longer than 8 seconds
        console.log(error.name);
      }
    }
    
    executeRequest(); 
    // if the request takes more than 8 seconds
    // logs "AbortError"
    

    在这个示例中,对/movies.json的请求需要超过8秒。

    decoratedFetch('/movies.json'),由于TimeoutFetcherDecorator,抛出超时错误。

    现在基本的获取器被封装在2个装饰器中:一个提取JSON对象,另一个在8秒内超时请求。这极大地简化了decoratedFetch()的使用:当调用decoratedFetch()时,decorator逻辑将为你工作。

    5. 总结

    fetch() API提供了执行获取请求的基本功能。但你需要的不止这些。单独使用fetch()强制你手动从请求中提取JSON数据,配置超时,等等。

    为了避免样板文件,你可以使用更友好的库,如axios。然而,使用像axios这样的第三方库会增加应用包的大小,同时你也会与之紧密结合。

    另一种解决方案是在fetch()上面应用装饰器模式。您可以创建从请求中提取JSON、超时请求等等的装饰器。你可以随时组合、添加或删除装饰器,而不会影响使用装饰器的代码。


    起源地下载网 » 使用装饰器模式强大你的 fetch

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元