美文网首页
js 动态加载

js 动态加载

作者: clmll | 来源:发表于2020-11-09 16:06 被阅读0次

    js 脚本懒加载,类似于webpack import()方法,可以适用于静态js文件的加载

    脚本文件

    type FetchSuccess = {
      success: boolean;
      loading: boolean;
      name: string;
      script: any;
    };
    
    // 加载脚本
    // name 名字,用来判断是否加载过
    // src 地址
    // timeOut 超时时间
    const fetchScript = (() => {
      const fetchSuccessList: FetchSuccess[] = [];
      return function fetchFn(
        name: string,
        src: string,
        timeOut: number = 5000,
      ): Promise<{ success: boolean }> {
        return new Promise(resolve => {
          const isCaching = fetchSuccessList.find(item => item.name === name);
          if (isCaching === undefined) {
            fetchSuccessList.push({ name, loading: true, success: false, script: null });
          }
          const current = fetchSuccessList.find(item => item.name === name) as any;
          // 代表之前已经获取过,就直接返回成功
          if (current.success) {
            resolve({ success: true });
            return;
          }
          if (current.script) {
            /**
             * 这里可能并发调用这个函数,同时调用三次,第一个先进来创建 script,
             * 后面的就不应该在创建 script,
             * 避免重复创建script, 等待第一次 onload
             */
            // setTimeout 实现
            function callback() {
              return new Promise(newResolve => {
                setTimeout(() => {
                  // 超时
                  if (new Date().getTime() - current.time >= timeOut) {
                    newResolve();
                    return;
                  }
                  // loading 结束
                  if (current.loading === false) {
                    newResolve();
                    return;
                  }
                  // 这里需要递归执行自己进行等待,直到前面两个断言进去后才执行最外层的 resolve
                  callback().then(() => callback());
                }, 50);
              }).then(() => {
                resolve({ success: current.success });
              });
            }
            callback();
            // setInterval 实现
            // new Promise(newResolve => {
            //   const timer = setInterval(() => {
            //     // 超时
            //     if (new Date().getTime() - current.time >= timeOut){
            //       newResolve(timer);
            //       return;
            //     }
            //     // loading 结束
            //     if (current.loading === false) {
            //       newResolve(timer);
            //       return;
            //     }
            //   }, 50);
            // }).then((timer: any) => {
            //   clearInterval(timer);
            //   resolve({ success: current.success });
            // });
            return;
          }
          current.script = document.createElement('script');
          current.loading = true;
          current.time = new Date().getTime();
          const { script } = current;
          script.src = src;
          document.body.appendChild(script);
          console.time(name + ':脚本加载时间');
          script.onload = () => {
            console.timeEnd(name + ':脚本加载时间');
            current.success = true;
            current.loading = false;
            resolve({ success: true });
          };
          script.onerror = () => {
            console.timeEnd(name + ':脚本加载时间');
            document.body.removeChild(script);
            current.script = null;
            current.success = false;
            current.loading = false;
            resolve({ success: false });
          };
        });
      };
    })();
    
    export default fetchScript;
    
    

    使用方式,封装echarts高阶组件,echarts从props里面取,统一管理echarts的加载方式,也可以用webpack
    import()替换,webpack的需要增加包下载和打包时间和修改publicPath

    import React, { PureComponent } from 'react';
    import fetchScript from '@/util/fetchScript';
    
    const echartsUrl = 'xxx'; // 你的静态文件地址
    
    const echartsHoc = Component => {
      return class Index extends PureComponent {
        static echarts = null;
    
        state = {
          echarts: Index.echarts,
        };
    
        async componentDidMount() {
          // 防止多 setState 一次
          if (Index.echarts) {
            return;
          }
          const { success } = await fetchScript('echarts', echartsUrl);
          if (!success) {
            return;
          }
          Index.echarts = window.echarts || null;
          this.setState({
            echarts: Index.echarts,
          });
        }
    
        render() {
          const { echarts } = this.state;
          if (echarts === null) {
            return null;
          }
          return <Component {...this.props} echarts={echarts} />;
        }
      };
    };
    
    export default echartsHoc;
    
    

    相关文章

      网友评论

          本文标题:js 动态加载

          本文链接:https://www.haomeiwen.com/subject/nkolbktx.html