【问题标题】:How to use promises, or complete an ajax request before the function finishes?如何在函数完成之前使用 Promise 或完成 ajax 请求?
【发布时间】:2019-12-27 03:20:17
【问题描述】:

我有以下功能来检查用户会话以查看他们是否是员工。现在,我知道有更好的方法可以做到这一点,但我正在尝试制作一个与论坛软件绑定的简单应用程序。

function isStaff(callback) {
    $.ajax({
        url: url
    }).done(function(data) {
        var session = $.parseJSON(data);
        if (session.is_staff === 1) {
            callback(true);
        } else {
            callback(false);
        }

    });
}

假设我在编译“帖子”(Handlebars)时使用了这个函数。

function compilePost(post) {
    var source = $('#feed-item-template').html();
    var template = Handlebars.compile(source);
    var context = {
        id: post.id,
        content: post.text,
        author: post.author,
        date: $.timeago(post.date),
        staff: function() {
            isStaff(function(response) {
                return response;
            });
        }
    }
    var html= template(context);
    return html;
}

这里的问题是,检查用户是否为员工的请求直到函数运行后才完成请求。

我知道 Promises 是 async: false 的替代方案,其中发出请求并在函数完成之前返回响应。

但我不知道如何将其转换为承诺。我试图学习它,但我坚持这个概念。谁可以给我解释一下这个?谢谢。

【问题讨论】:

    标签: javascript jquery promise


    【解决方案1】:

    首先,让我们简化compilePost 函数。该函数应该知道如何以同步方式编译帖子。让我们将 isStaff 获取更改为一个简单的参数。

    function compilePost(post, isStaff) {
        var source = $('#feed-item-template').html();
        var template = Handlebars.compile(source);
        var context = {
            id: post.id,
            content: post.text,
            author: post.author,
            date: $.timeago(post.date),
            staff: isStaff
        }
    
        var html= template(context);
        return html;
    }
    

    现在,让我们创建一个新方法,其目的只有一个 - 检查用户是否是员工:

    function checkForStaffMemebership() {
        return new Promise(function (resolve, reject) {
            $.ajax({
                url: url,
                success: function (data) {
                    var session = $.parseJSON(data);
                    if (session.is_staff === 1) {
                        resolve(true);
                    } else {
                        resolve(false);
                    }
                }
            });
        });
    }
    

    这个函数用一个promise包装你对服务器的原始ajax调用,每当$.ajax调用从服务器得到响应时,无论用户是否是工作人员,promise都会以答案解析。

    现在,我们可以编写另一个函数来编排流程:

    function compilePostAsync(post) {
        return checkForStaffMemebership()
            .then(function (isStaff) {
                return compilePost(post, isStaff);
            });
    }
    

    compilePostAsync 判断用户是否为员工。然后,它正在编译帖子。

    请注意 compilePostAsync 返回一个承诺,因此如果你曾经有过类似的东西:

    element.innerHTML = compilePost(post);
    

    现在,您应该将其更改为:

    compilePostAsync(post).then(function (compiledPost) {
        element.innerHTML = compiledPost;
    });
    

    一些注意事项:

    1. 这只是一个例子,它肯定会遗漏一些东西(例如正确的错误处理)
    2. isStaffcheckForStaffMemebership(原版和新版)没有任何参数,我想您会弄清楚如何传递 userId 或您可能需要的任何其他数据
    3. 了解 promises,这是一个有用的工具,网上有很多关于它的数据,例如:MDN

    【讨论】:

    • “现在,我们可以编写另一个函数来编排流程”......在什么情况下我需要一个函数来“编排流程”?这对我来说很有趣。
    【解决方案2】:

    根据documentation,您不需要用已经实现承诺的承诺包装 ajax。而是按照下面的说明链接响应。

    从 jQuery 1.5 开始,由 $.ajax() 返回的 jqXHR 对象实现了 Promise 接口,为它们提供了 Promise 的所有属性、方法和行为(有关更多信息,请参阅延迟对象)

    您可以通过链接响应来执行以下操作:

    function isStaff(url, post) {
        return $.ajax({
            url: url,
            dataType:"json"
        }).then(function(resp){
            //resp = $.parseJSON(resp); /*You dont require this if you have respose as JSON object. Just Specify it in 'dataType'*/
            var source = $('#feed-item-template').html();
            var template = Handlebars.compile(source);
            var context = {
                id: post.id,
                content: post.text,
                author: post.author,
                date: $.timeago(post.date),
                staff: resp.is_staff === 1 ? true : false
            };
    
            return template(context);
        });
    }
    
    isStaff(url, post).done(function(template){
        /*Your compiled template code is available here*/
    }).fail(function(jqXHR, textStatus, errorThrown){
       console.log("Error:"+textStatus);
    });
    

    注意:请务必同时实现error callbacks。因为你可能永远不知道什么 出错了:)


    用$.defer简单解释promise:

    为了理解,我创建了类似于您的要求的Fiddle

    说明:

    基本上引入了Promise来实现异步JS代码的同步执行。

    异步或异步代码是什么意思?

    执行的代码可能会在任何给定的时间点返回一个非立即的值。支持这种说法的著名例子是jquery ajax

    为什么需要它?

    Promise 实现帮助开发人员实现一个同步代码块,该同步代码块依赖于异步代码块进行响应。就像在 ajax 调用中,当我向服务器发出请求数据字符串的请求时,我需要等到服务器用响应数据字符串回复我,我的同步代码使用它来操作它,执行一些逻辑并更新 UI .

    关注link,作者已通过详细示例进行了解释。

    PS: Jquery $.defer 以完全不同的方式实现或包装promise。两者的用途相同。

    【讨论】:

      【解决方案3】:
      let basedataset = {}
      let ajaxbase = {};
      //setting api Urls
      apiinterface();
      
      function apiinterface() {
          ajaxbase.createuser = '/api/createuser'
      }
      //setting up payload for post method
      basedataset.email = profile.getEmail()
      basedataset.username = profile.getGivenName()
      //setting up url for api 
      ajaxbase.url = ajaxbase.createuser
      ajaxbase.payload = basedataset;
      
      //reusable promise based approach 
      basepostmethod(ajaxbase).then(function(data) {
          console.log('common data', data);
      }).catch(function(reason) {
          console.log('reason for rejection', reason)
      });
      //modular ajax (Post/GET) snippets
      function basepostmethod(ajaxbase) {
      
          return new Promise(function(resolve, reject) {
              $.ajax({
                  url: ajaxbase.url,
                  method: 'post',
                  dataType: 'json',
                  data: ajaxbase.payload,
                  success: function(data) {
                      resolve(data);
                  },
                  error: function(xhr) {
                      reject(xhr)
                  }
      
              });
          });
      }
      

      【讨论】:

        【解决方案4】:

        在 js 中使用 async await 的解决方案是这样的:

        async function getMyAjaxCall() {
          const someVariableName = await ajaxCallFunction();
        }
        
        function getMyAjaxCall() {
            return $.ajax({
            type: 'POST',
            url: `someURL`,
            headers: {
              'Accept':'application/json',
          },
            success: function(response) {
        // in case you need something else done.
            }
            });
        }
        

        【讨论】:

          猜你喜欢
          • 2018-07-24
          • 2020-03-14
          • 1970-01-01
          • 2011-11-17
          • 2014-12-01
          • 2019-03-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多