前后分离模型之封装 Api 调用

小结

正文以封装 Ajax 调用为例,看似在描述异步调用。但实在想告诉我们的东西是:怎么样将贰个常用的作用封装起来,完成代码重用和更简短的调用;以及在卷入的进程中须求思索的标题——向前和向后的宽容性,在做工具函数封装的时候,应该尽量幸免和某些特定的工具性情绑定,向公共标准靠拢——不知大家是或不是具备体会。

去除 jQuery

就只在那边运用 jQuery 总令人深感如芒在背,想把它去掉。有多个办法

    1.改变不论什么事务中的调用,去掉 .done()、.fail() 和 .always(),改成 .then()。这一步专业量十分的大,但宗旨无痛,因为 jQuery Promise 本身协理.then()。但是有点内需非常注意,这点稍后证实
    2.谈得来写个适配器,包容 jQuery Promise 的接口,专门的工作量也十分大,但主假诺要尽量测量试验,防止差错。
地点提到第 1 种方法中有点亟需特别注意,那正是 .then() 和 .done() 体系函数在管理格局上有所区别。.then() 是按 Promise 的天性设计的,它回到的是另三个 Promise 对象;而 .done() 体系函数是按事件机制达成的,重临的是原来的 Promise 对象。所以像上边那样的代码在修改时将在小心了

appAjax(url, params)
    .done(function(data) { console.log("第 1 处处理", data) })
    .done(function(data) { console.log("第 2 处处理", data) });
// 第 1 处处理 {}
// 第 2 处处理 {}

轻便易行的把 .done() 改成 .then() 之后(注意没有必要运用 Bluebird,因为 jQuery Promise 帮助 .then())

appAjax(url, params)
    .then(function(data) { console.log("第 1 处处理", data); })
    .then(function(data) { console.log("第 2 处处理", data); });
// 第 1 处处理 {}
// 第 2 处处理 undefined

缘由上边已经讲了,那士大夫确的管理格局是统一多少个 done 的代码,或然在 .then() 处理函数中回到 data:

appAjax(url, params)
    .then(function(data) {
        console.log("第 1 处处理", data);
        return data;
    })
    .then(function(data) {
        console.log("第 2 处处理", data);
    });

Ajax 和异步管理

调用 API 访谈数据选用的 Ajax 情势,那是三个异步进程,异步进度最中央的管理方式是事件或回调,其实这三种管理方式完成原理大概,都急需在调用异步进度的时候传出三个在异步进度甘休的时候调用的接口。比方jQuery Ajax 的 success 正是卓尔不群的回调参数。不过使用 jQuery 管理异步推荐应用 Promise 管理方式。

Promise 处理格局也是透过注册回调函数来变成的。jQuery 的 Promise 和 ES6 的正式 Promise 有一点不同,但在 then 上可以同盟,经常称为 thenable。jQuery 的 Promise 未有提供 .catch() 接口,但它协和定义的 .done()、.fail() 和 .always() 几个注册回调的诀要也很有风味,用起来很便利,它是在事件的措施来注册的(即,能够登记八个同类别的管理函数,在该触发的时候都会接触)。

本来越来越直观的某个的管理情势是接纳 ES2017 带来的 async/await 格局,能够用协同代码的方式来写异步代码,当然也可能有一部分坑在里面。对于前端程序员来说,最大的坑正是某些浏览器不支持,须要张开转译,所以只要前端代码未有塑造进程,日常如故就用 ES5 的语法包容性好一些(jQuery 的 Promise 是永葆 ES5 的,可是正式 Promise 要 ES6 今后才方可选用)。

有关 JavaScript 异步管理相关的从头到尾的经过能够参见

  • 从异常的小题目稳步走进 JavaScript 异步调用

  • 闲谈异步调用“扁平”化

  • 从鬼世界到天国,Node 回调向 async/await 转换

  • 理解 JavaScript 的 async/await

  • 从毫无 try-catch 落成的 async/await 语法说错误处理

改动 API 调用接口

上边包车型地铁包装对调用接口和再次回到数据开展了联合管理,把大多数品类接口约定的内容都管理掉了,剩下在历次调用时需求处理的正是纯粹的业务。

明天项目组决定决不 jQuery 的 Ajax,而是接纳 axios 来调用 API(axios 不见得就比 jQuery 好,这里只是比喻),那么只须求修改一下 appAjax() 的兑现就能够。全部业务调用都无需修改。

只要以后的目的境遇照旧是 ES5,那么须求第三方 Promise 提供,这里拟用 Bluebird,包容原生 Promise 接口(在 HTML 中引进,未直接出现在 JS 代码中)。

function appAjax(action, params) {
    var deffered = $.Deferred();

    axios
        .post(apiUrl, {
            data: $.extend({
                action: action
            }, params)
        })
        .then(function(data) { ... }, function() { ... });

    return deferred.promise();
}

此番的包裹选取了 axios 来兑现 Web Api 调用。可是为了保持原本的接口(jQuery Promise 对象有提供 .done()、.fail() 和 .always() 事件管理),appAjax 依旧只可以再次来到 jQuery Promise。那样,尽管具备地点都不再须求选择 jQuery,这里仍然得用。

花色中应有用依然不要 jQuery?请阅读为啥要用原生 JavaScript 代替jQuery?

和煦包裹工具函数

在管理 Ajax 的进度中,即便有现存的库(譬喻 jQuery.ajax,axios 等),它毕竟是为着通用目标设计的,在应用的时候依然免不了繁琐。而在品种中,对 Api 进行调用的进度大致都大同小异。假诺规划相符,就连错误管理的形式都会是一律的。因此,在项目内的 Ajax 调用实际能够张开更进一竿的包裹,使之在品种内选取起来更有益于。如果接口格局爆发变化,修改起来也更易于。

例如,当前接口须要利用 POST 方法调用(暂不挂念 RESTful),参数必需概括action,重临的多寡以 JSON 情势提供,假如出错,只要不是服务器万分都会回来特定的 JSON 数据,满含三个不对等 0 的 code 和可选的 message 属性。

那么用 jQuery 写那样三个 Ajax 调用,大致是那般

const apiUrl = "http://api.some.com/";

jQuery
    .ajax(url, {
        type: "post",
        dataType: "json",
        data: {
            action: "login",
            username: "uname",
            password: "passwd"
        }
    })
    .done(function(data) {
        if (data.code) {
            alert(data.message || "登录失败!");
        } else {
            window.location.assign("home");
        }
    })
    .fail(function() {
        alert("服务器错误");
    });

应用 Promise 接口改革陈设

我们的 appAjax() 接口部分也足以安插成 Promise 完成,这是二个更通用的接口。既使用不用 ES二零一六+ 天性,也得以使用像 jQuery Promise 或 Bluebird 那样的三方库提供的 Promise。

function appAjax(action, params) {
    // axios 依赖于 Promise,ES5 中可以使用 Bluebird 提供的 Promise
    return axios
        .post(apiUrl, {
            data: $.extend({
                action: action
            }, params)
        })
        .then(function(data) {
            // 这里调整了判断顺序,会让代码看起来更简洁
            if (!data.code) { return data; }
            if (!data.message) { throw data; }
            alert(data.message);
        }, function() {
            alert("服务器错误");
        });
}

而是现在前端有创设筑工程具,能够动用 ES二零一六+ 配置 Babel,也能够选用TypeScript …… 总来讲之,选择过多,写起来也很实惠。那么在统一企图的时候就绝不局限于 ES5 所支持的内容了。所以能够思考用 Promise + async/await 来完毕

async function appAjax(action, params) {
    // axios 依赖于 Promise,ES5 中可以使用 Bluebird 提供的 Promise
    const data = await axios
        .post(apiUrl, {
            data: $.extend({
                action: action
            }, params)
        })
        // 这里模拟一个包含错误消息的结果,以便后面统一处理错误
        // 这样就不需要用 try ... catch 了
        .catch(() => ({ code: -1, message: "服务器错误" }));

    if (!data.code) { return data; }
    if (!data.message) { throw data; }

    alert(data.message);
}

地点代码中采取 .catch() 来幸免 try ... catch ... 的技术在从毫无 try-catch 达成的 async/await 语法说错误管理中关系过。

当然业务层调用也足以行使 async/await(记得写在 async 函数中):

const data = await appAjax("login", {
    username: "uname",
    password: "passwd"
}).catch(() => {
    alert("登录失败");
});

if (data) {
    window.location.assign("home");
}

对此频仍 .done() 的改建:

const data = await appAjax(url, params);
console.log("第 1 处处理", data);
console.log("第 2 处处理", data);

初步封装

同样类型中,这样的 Ajax 调用,基本上唯有 data 部分和 .done 回调中的 else 部分不相同,所以实行三次封装会大大减弱代码量,能够那样封装

function appAjax(action, params) {
    var deffered = $.Deferred();

    jQuery
        .ajax(apiUrl, {
            type: "post",
            dataType: "json",
            data: $.extend({
                action: action
            }, params)
        })
        .done(function(data) {
            // 当 code 为 0 或省略时,表示没有错误,
            // 其它值表示错误代码
            if (data.code) {
                if (data.message) {
                    // 如果服务器返回了消息,那么向用户呈现消息
                    // resolve(null),表示不需要后续进行业务处理
                    alert(data.message);
                    deffered.resolve();
                } else {
                    // 如果服务器没返回消息,那么把 data 丢给外面的业务处理
                    deferred.reject(data);
                }
            } else {
                // 正常返回数据的情况
                deffered.resolve(data);
            }
        })
        .fail(function() {
            // Ajax 调用失败,向用户呈现消息,同时不需要进行后续的业务处理
            alert("服务器错误");
            deffered.resolve();
        });

    return deferred.promise();
}

而业务层的调用就很简短了

appAjax("login", {
    username: "uname",
    password: "passwd"
}).done(function(data) {
    if (data) {
        window.location.assign("home");
    }
}).fail(function() {
    alert("登录失败");
});

本文由开元棋牌发布于服务器&运维,转载请注明出处:前后分离模型之封装 Api 调用

TAG标签:
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。