zoukankan      html  css  js  c++  java
  • 用Promise解决多个异步Ajax请求导致的代码嵌套问题【转】

    问题

    前端小同学在做页面的时候,犯了个常见的错误:把多个Ajax请求顺序着写下来了,而后面的请求,对前面请求的返回结果,是有依赖的。如下面的代码所示:

    var someData;
    $.ajax({
                url: '/prefix/entity1/action1',
                type: 'GET' ,
                async: true,
                contentType: "application/json",
                success: function (resp) {
                    //do something on response
                   someData.attr1 = resp.attr1;
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    //在这个页面里,所有的请求的错误都做同样的处理
                    if (XMLHttpRequest.status == "401") {
                        window.location.href = '/login.html';
                    } else {
                        alert(XMLHttpRequest.responseText);
                    }
                }
            });
    
    $.ajax({
                url: '/prefix/entity2/action2',
                type: 'POST' ,
                dataType: "json",
                data: JSON.stringify(someData),
                async: true,
                contentType: "application/json",
                success: function (resp) {
                    //do something on response
                 },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    //在这个页面里,所有的请求的错误都做同样的处理
                    if (XMLHttpRequest.status == "401") {
                        window.location.href = '/login.html';
                    } else {
                        alert(XMLHttpRequest.responseText);
                    }
                }
            });

    以上代码有两个问题:
    *首先就是执行顺序不能保证,action2很可能在action1返回之前就发出了,导致someData.attr1这个参数没能正确传出
    *其次两个ajax请求的代码重复很严重

    思路

    • 代码重复的问题相对好解决,尤其是在自己的项目里,各种参数可以通过规范定死,封装一个参数更少的ajax方法就好了
     1 //url:地址
     2 //data:数据对象,在函数内部会转化成json串,如果没传,表示用GET方法,如果传了,表示用POST方法
     3 function ajax(url, data, callback) {
     4         $.ajax({
     5             url: url,
     6             type: data == null ? 'GET' : 'POST',
     7             dataType: "json",
     8             data: data == null ? '' : JSON.stringify(data),
     9             async: true,
    10             contentType: "application/json",
    11             success: function (resp) {
    12                 callback(resp);
    13             },
    14             error: function (XMLHttpRequest, textStatus, errorThrown) {
    15                 if (XMLHttpRequest.status == "401") {
    16                     window.parent.location = '/enterprise/enterprise_login.html';
    17                     self.location = '/enterprise/enterprise_login.html';
    18                 } else {
    19                     alert(XMLHttpRequest.responseText);
    20                 }
    21             }
    22         });
    23 }
    • 这样只有url,data和callback三个必要的参数要填,其他都定死了
    • 执行顺序的问题,可以把第二个请求放在第一个请求的回调里,形如:
    1 ajax('/prefix/entity1/action1',null, function(resp){
    2      //do something on response
    3      someData.attr1 = resp.attr1;
    4      ajax('/prefix/entity2/action2', someData, function(resp){
    5           //do something on response
    6      }
    7 };

    至此问题似乎解决得很完美,但可以想见,如果请求不止两个,而是4、5个,同时还有其他异步操作(比如我们的页面里有Vue对象的初始化),相互之间有依赖关系,光是这样层层叠叠的括号嵌套,就已经让人头晕了。

    需要找到一种方法,让异步调用的表达看起来像同步调用一样。

    正好最近看了阮一峰老师关于ES6的书,而且用户也没有强硬要求兼容IE浏览器,于是就选择了Promise的方案

    解决方案

      • 引入Promise
        其实现代浏览器都已经内置支持了Promise,连第三方库都不需要了,只有IE不行,放弃了

      • 改造ajax封装函数,在成功的时候调用resolve(),失败的时候调用reject(),并且返回Promise对象

     1 function ajax(url, data, callback) {
     2     var p = new Promise(function (resolve, reject) {
     3         $.ajax({
     4             url: url,
     5             type: data == null ? 'GET' : 'POST',
     6             dataType: "json",
     7             data: data == null ? '' : JSON.stringify(data),
     8             async: true,
     9             contentType: "application/json",
    10             success: function (resp) {
    11                 callback(resp);
    12                 resolve();
    13             },
    14             error: function (XMLHttpRequest, textStatus, errorThrown) {
    15                 if (XMLHttpRequest.status == "401") {
    16                     window.parent.location = '/enterprise/enterprise_login.html';
    17                     self.location = '/enterprise/enterprise_login.html';
    18                 } else {
    19                     alert(XMLHttpRequest.responseText);
    20                 }
    21                 reject();
    22             }
    23         });
    24     });
    25     return p;
    26 }
    • 修改调用端
     1 ajax('/prefix/entity1/action1',null, function(resp){
     2      //do something on response
     3      someData.attr1 = resp.attr1;
     4 }).then(
     5      ajax('/prefix/entity2/action2', someData, function(resp){
     6           //do something on response
     7      }
     8 ).then(
     9      initVue() ;
    10 ).then(
    11      //do  something else
    12 )

    至此完美解决。


    经@miroki 提醒,发现Jquery从1.5版开始,返回的就是thenable对象了,那么ajax函数可以直接返回$.ajax()的返回值

    本文转自:https://segmentfault.com/a/1190000008486570

  • 相关阅读:
    2.12 使用@DataProvider
    2.11 webdriver中使用 FileUtils ()
    Xcode8 添加PCH文件
    The app icon set "AppIcon" has an unassigned child告警
    Launch Image
    iOS App图标和启动画面尺寸
    iPhone屏幕尺寸、分辨率及适配
    Xcode下载失败 使用已购项目页面再试一次
    could not find developer disk image
    NSDate与 NSString 、long long类型的相互转化
  • 原文地址:https://www.cnblogs.com/mmzuo-798/p/7821716.html
Copyright © 2011-2022 走看看