当处理 Ajax 的历程被。异步过程绝核心的处理方式是事件或者回调。

好包装工具函数

在拍卖 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("服务器错误");
    });

转移 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);
    });

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 调用,基本上就发 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("登录失败");
});

应用 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 和异步处理

调用 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
调用为条例,看似在描述异步调用。但事实上想报大家的东西是:如何用一个常用之功效封装起来,实现代码用和更简明之调用;以及以卷入的历程被得考虑的题材——向前同通往后底兼容性,在开工具函数封装的时候,应该尽量避免和有特定的工具特性绑定,向公共规范靠拢——不知大家是否有所体会。

小结

正文为封装 Ajax
调用为条例,看似在叙异步调用。但事实上想报大家之事物是:如何以一个常用的效能封装起来,实现代码用和更简明的调用;以及在包的历程被得考虑的题目——向前同向阳后底兼容性,在召开工具函数封装的时,应该尽量避免和有特定的工具特性绑定,向国有规范靠拢——不知大家是不是具备体会。

祥和包工具函数

每当处理 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("登录失败");
});

用 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);

相关文章