关于javascript:Loading-done

17次阅读

共计 2190 个字符,预计需要花费 6 分钟才能阅读完成。

引子

在后面界面开发的过程中,为了加强在与后端交互过程中的用户体验,通常会显示 Loading 动画。Loading 动画会在与后端交互完结的时候敞开。这是一个很惯例的需要,技术实现也不简单。

showLoading();
axios.request(...)
    .then(...)
    .finally(() => hideLoading());

Node.js 和大部分浏览器都在 2018 年实现了对 Promise.prototype.finally() 的反对。Deno 在 2020 年公布的 1.0 中也曾经反对 finally() 了。即便不反对,应用 await 也很容易解决。

showLoading()
try {await axios.request(...);
}
finally {hideLoading();
}

而在更早的时候,jQuery 在 jqXHR 中就曾经通过 always() 提供了反对。

showLoading();
$.ajax(...)
    .done(...)
    .always(() => hideLoading());

拦截器中的 Loading … done 逻辑

接下来,为了所有接口调用的行为统一,也为了在一个中央解决雷同的事件以达到复用的目标,Loading … done 的逻辑开始被写在一些拦截器中。这对单个近程接口调用来说,没有问题。但如果有这样一个业务逻辑会怎么样:

function async doSomething() {const token = await fetchToken();
    const auth = await remoteAuth(token);
    const result = await fetchBusiness(auth);
}

假如下面的每个调用都应用了 Axios,而 Axios 在拦截器中注入了 showLoading()hideLoading() 的逻辑。那么这段代码会顺次弹出三个 Loading 动画。一个业务弹多个 Loading 动画的确是个不太好的体验。

给 Loading 记数

其实这个问题咱们能够在 showLoading()hideLoading() 中去想方法。咱们把这两个办法放入一个闭包环境,而后用一个变量来记录调用次数:

const {showLoading, hideLoading} = (() => {
    let count = 0;
    function showLoading() {
        count++;
        if (count > 1) {return;}
        // TODO show loading view
    }
    function hideLoading() {
        count--;
        if (count > 1) {return;}
        // TODO hide loading view
    }
})();

包装业务逻辑代替拦截器计划

作者观点

我集体并不同意在拦截器里去解决界面上的事件。拦截器中应该解决与申请自身强相干的事件,比方对参数的预处理,对响应的后处理等。

我不太同意在拦截器中去解决界面上的货色。像这种状况,能够设计一个 wrap 函数来解决 Loading 的出现并调用通过参数传入的业务逻辑。这个 wrap 函数能够这样写:

async function wrapLoading(fn) {showLoading();
    try {return await fn();
    }
    finally {hideLoading();
    }
}

在应用的时候能够这样用:

// 单个近程调用,不带参数
await wrapLoading(fetchSomething);

// 单个近程调用,带参数
await wrapLoading(() => fetchSomething(arg1, arg2, arg3));

// 多个调用的组合逻辑
const result = await wrapLoading(() => {const token = await fetchToken();
    const auth = await remoteAuth(token);
    return await fetchBusiness(auth);
});

下沉包装函数升高业务解决复杂度

为了利用内更自在地统一化解决,倡议对底层 Ajax 框架进行一次封装。业务近程调用时应用封装的接口,防止间接应用 Ajax 库接口。比方对 Axios request 进行一层封装。

async function request(url, config) {
    config.url = url;
    return await axios.request(config);
}

如果须要显示 Loading,能够扩大 config,加一个 withLoading 选项:

async function request(url, config) {const { withLoading, ...cfg} = config;
    cfg.url = url;
    
    if (!withLoading) {return await axios.request(cfg); }

    try {showLoading();
        return await axios.request(cfg);
    }
    finally {hideLoading();
    }
}

如果扩大的业务参数比拟多,能够思考封装成一个对象,比方 config.options,也能够给封装的 request 多加一个参数:request(url, config, options),这些实现都不难,就不细说了。

有了这层封装之后,如果当前想更换 Ajax 框架也绝对容易,只须要批改封装的 request 函数即可,做到了业务层与框架 / 工具的解耦。

正文完
 0