葡京娱乐平台内外分离型的封装 Api 调用。前后分离型的封装 Api 调用。

在处理 Ajax 的过程中,异步过程最基本的处理方式是事件或回调

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
    语法说错误处理

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
    语法说错误处理

友善包装工具函数

以处理 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("服务器错误");
    });

好包工具函数

于处理 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("服务器错误");
    });

起来封装

一律型遭到,这样的 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("登录失败");
});

发端封装

同样品种中,这样的 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 调用接口

点的包裹对调用接口和归数据开展了统一处理,把大部分种接口约定的情节还处理掉了,剩下在历次调用时得处理的即是纯粹的政工。

现行项目组决定不要 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?

转换 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?

去除 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);
    });

去除 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);
    });

用 Promise 接口改进计划

咱的 appAjax() 接口部分吗可以计划成 Promise
实现,这是一个再度通用的接口。既使不用 ES2015+ 特性,也堪运用像 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("服务器错误");
        });
}

可是本前端有构建工具,可以采取 ES2015+ 配置 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);

应用 Promise 接口改进计划

我们的 appAjax() 接口部分为堪设计成 Promise
实现,这是一个再次通用的接口。既使不用 ES2015+ 特性,也得采用诸如 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("服务器错误");
        });
}

然而本前端有构建工具,可以使 ES2015+ 配置 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
调用为条例,看似在叙述异步调用。但实则想告知大家的物是:如何将一个常用的功效封装起来,实现代码用和重复简洁的调用;以及在包的历程中得考虑的问题——向前同向阳后的兼容性,在做工具函数封装的时刻,应该尽量避免和某特定的工具特性绑定,向公共规范靠拢——不知大家是否有所体会。

小结

本文为封装 Ajax
调用为例,看似在讲述异步调用。但骨子里想告知大家之物是:如何以一个常用之效果封装起来,实现代码用和还简明之调用;以及在包的历程中待考虑的问题——向前同通往后底兼容性,在举行工具函数封装的早晚,应该尽量避免和某特定的工具特性绑定,向国有规范靠拢——不知大家是不是具有体会。