如何在函数完成之前使用promises或完成ajax请求?

时间:2016-06-10 07:00:01

标签: javascript jquery promise

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

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;
}

问题在于,检查用户是否是工作人员的请求直到函数运行后才完成请求。

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

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

4 个答案:

答案 0 :(得分:14)

首先,让我们简化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);
                }
            }
        });
    });
}

此函数将原始ajax调用包含在承诺的服务器中,每当$.ajax调用从服务器获得响应时,承诺将通过答案解决,无论用户是否为工作人员或不。

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

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. 阅读承诺,这是一个有用的工具,网上有很多关于它的数据,例如:MDN

答案 1 :(得分:0)

根据documentation,您不需要使用已经实现promise的promise来包装ajax。而是将响应链接起来,如下所述。

  

jQuery 1.5中$ .ajax()返回的jqXHR对象实现了Promise接口,为它们提供了Promise的所有属性,方法和行为(有关详细信息,请参阅Deferred对象)

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

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的承诺的简单解释:

为了理解我已经创建了与您的要求类似的Fiddle

说明:

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

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

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

为什么需要?

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

按照作者解释的link详细说明。

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

答案 2 :(得分:0)

COPY

答案 3 :(得分:0)

在js中使用异步等待的解决方案如下:

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.
    }
    });
}