jQuery的异步编程模式? [英] jQuery Asynchronous programming pattern?

查看:148
本文介绍了jQuery的异步编程模式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我继承了扫描网页寻找数据属性和修改DOM,添加处理程序等,相应地。

应用程序

有人问我实现动态标记,由此我发出一个Ajax调用来获得JSON数据,然后使用把手呈现基于返回的数据的新的HTML。

我要告诉为主,外部应用程序要等到所有的JSON调用它去寻找数据属性之前已经得到解决。

我应该把什么样的格局到位做到这一点?

任何帮助将非常AP preciated。

谢谢,
斯科特

更新

outer.js - 扫描DOM找事情做。

inner.js - 问题0-9 Ajax调用(取决于我在页面上)。每次这些Ajax调用具有调用函数把手写一个标记。然后()函数。

如果我只是一个Ajax调用,我可以传回给inner.js作为outer.js一个推迟。然后,在阿贾克斯的。那么()函数,我只是叫inner.js.resolve()。

但是,如果我这样做是为每一个可能9的inner.js 1#运行后会解决,但在此之前#2完成。

我如何动态地设置一些推迟了outer.js使用要等到他们都解决了吗?

这似乎并不可能后期绑定一个这样的数组:

在inner.js的顶部:

  VAR应用= jQuery.Deferred();
变种arrayOfAsync = [];
application.done(arrayOfAsync);

然后,当jQuery选择在一个网页上找到,我可以做一个

  arrayOfAsync.push(localPromise);

但是,这似乎并没有工作...应该呢?这将假设递延()其实只是抱着一种正常的阵列,它可能不是...


解决方案

您应该使用在这种情况下的诺言。

假设你有你的车把模板:

 <脚本ID =PostsTempl类型=文/ X-车把模板>
    {{#each帖子}}
        <李班=项目,车把> {{}体}< /李>
    {{/每}}
< / SCRIPT>

这应该充满了一系列的从Web API / Web服务获取的帖子。

您将编译模板使用它之前:

  VAR MyTemplate的= Handlebars.compile($(#PostsTempl)HTML());

现在,我们需要一个函数,它会调用Web API / Web服务,将fetche一些数据:

 函数fetchData()
{
    变种推迟= $ .Deferred();    $阿贾克斯({
        输入:GET,
        数据类型:JSON,
        网址:'我的/ API /职位/ 1/20',
        数据:{},
        成功:函数(jsonData){
           如果(jsonData){
              deferred.resolve(jsonData);
           }其他{
              deferred.reject('');
           }
        },
        错误:功能(REQ,状态,错误){
            VAR的errorMessage =(返回Error.message)?返回Error.message:错误;
            deferred.reject(的errorMessage);
        }
    });    返回deferred.promise();}

我们将使用 $。阿贾克斯 GET 的数据。我们定义这里承诺的:

  VAR推迟= $ .Deferred();

当我们取回数据,这将得到解决:

 成功:函数(jsonData){
    如果(jsonData){
       deferred.resolve(jsonData);
    }其他{
       deferred.reject('');
    }
},

或者最终被拒绝,如果没有数据。

返回deferred.promise(); 将回到我们的承诺

现在,我们可以调用它解决的承诺并反馈一些数据的功能:

  fetchData()
    。然后(功能(数据){
        //的console.log(数据);
        VAR帖= {帖子:数据};
        $(#上岗)追加(MyTemplate的(岗位))。
        返回true;
    })
    。然后(功能(结果){
        goLookForDataAttributes();
    })
    .fail(函数(原因){
        如果(理由!==''){
            警报('出事了:'+原因);
        }
    });

当我们得到的数据传回,我们追加项目我们的模板:

 。然后(功能(数据){
    //的console.log(数据);
    VAR帖= {帖子:数据};
    $(#上岗)追加(MyTemplate的(岗位))。
    返回true;
})

当一切都做,我们调用另一个函数中的其他。然后()分行:

 。然后(功能(结果){
        goLookForDataAttributes();
    })

承诺可以链接。
第二个。然后()执行后,第一个被调用。

这是你需要的最后一点:

 函数goLookForDataAttributes()
{
    $('#帖子li.item-把手)。每个(函数(指数,项目){
        $(项目).addClass(大字体);
    });
}

小提琴可能会帮助你。

在这个例子中,我分析的职位,并添加一个类时的 handlebards 已呈现的元素。

更新:

既然你调用Web API / Web服务,您可以并行执行的承诺,等到所有的Ajax请求已经完成并执行最后一个方法。

为了简单起见,我将创建一个假的承诺(这应该是你的Ajax请求):

 函数buildPromise(ID)
{
    变种推迟= $ .Deferred();    的setTimeout(函数(){
        VAR数据= {ID:ID,名称:名称:+ ID};
        deferred.resolve(数据);
    },1000);    返回deferred.promise();
}

和我将创建一个数组,让我们说,10承诺:

  VAR承诺= [];为(变量p = 0时,P小于10,P +)
{
    promises.push(buildPromise(P));
}

现在我将能够并行运行这些承诺:

  $。when.apply($,许诺)
    。然后(函数(){
        对于(VAR I = 0; I<与arguments.length;我++){
            $('#内容)追加('< P>'+参数[I]。名称+'< / P>');
        }
    }),然后(功能(结果){
    返回finalPromise();
})
。然后(功能(结果){
    警报('成功:'+ result.success);
    警报('完成');
});

$。when.apply($,承诺)解决了所有的承诺一起,并行,并返回当我们回到所有结果。结果
结果可在参数中找到,并可以使用数组的索引参数[X]

在所有Ajax请求都被执行,我们将调用 finalPromise

 函数finalPromise()
{
    变种推迟= $ .Deferred();    的setTimeout(函数(){
        VAR数据= {成功:真正};
        deferred.resolve(数据);
    },1000);    返回deferred.promise();}

finalPromise 可能是一个普通的功能,没有承诺,也是如此。

是什么样子。

当然,现在你必须使其适应您的情况。

I have inherited an app that scans a page looking for data attributes and modifies the dom, adding handlers, etc, accordingly.

I was asked to implement dynamic markup whereby I issue an ajax call to get json data and then use Handlebars to render the new html based on the returned data.

I need to tell the main, outer app to wait until all of the json calls have been resolved before it goes looking for data attributes.

What sort of pattern should I put in place to do this?

Any help would be very much appreciated.

Thanks, Scott

Update

outer.js - scans DOM looking for things to do.

inner.js - issues 0-9 ajax calls (depending on the page I'm on). Each of those ajax call has a .then() function that calls Handlebars functions to write markup.

If I just had a single ajax call, I could pass back inner.js to outer.js as a deferred. Then, in that ajax's .then() function, I'd just call inner.js.resolve().

But if I did this for each of the 9 possible inner.js would resolve after #1 runs, but before #2 finishes.

How do I dynamically set the number of deferred that the outer.js uses to wait until they are ALL resolved?

It doesn't seem possible to late-bind an array like this:

at top of inner.js:

var application = jQuery.Deferred();
var arrayOfAsync = [];
application.done(arrayOfAsync);

Then, when jQuery selectors are found on a page, I could do an

arrayOfAsync.push(localPromise);

But this didn't seem to work... should it? This would assume that the Deferred() is really just holding on to a normal array, which it might not be...

解决方案

You should use promises in this situation.

Let's say you have your handlebars template:

<script id="PostsTempl" type="text/x-handlebars-template">
    {{#each posts}}
        <li class="item-handlebars">{{body}}</li>
    {{/each}}
</script>

which should be filled with a series of posts fetched from a web api/web service.

You will compile the template before using it:

var myTemplate = Handlebars.compile($("#PostsTempl").html());

Now we need a function which will call the web api/web service and will fetche some data:

function fetchData()
{
    var deferred = $.Deferred();

    $.ajax({
        type: 'GET',
        dataType: 'json',
        url: 'my/api/posts/1/20',
        data: {},
        success: function (jsonData) {
           if (jsonData) {
              deferred.resolve(jsonData);
           } else {
              deferred.reject('');
           }
        },
        error: function (req, status, error) {
            var errorMessage = (error.message) ? error.message : error;
            deferred.reject(errorMessage);
        }
    });

    return deferred.promise();

}

We will use $.ajax to GET the data. We have defined a promise here:

var deferred = $.Deferred();

which will be resolved when we get the data back:

success: function (jsonData) {
    if (jsonData) {
       deferred.resolve(jsonData);
    } else {
       deferred.reject('');
    }
},

Or eventually, rejected, if there's no data.

return deferred.promise(); will return our promise.

Now we can call the function which resolves the promise and feeds back some data:

  fetchData()
    .then(function(data){
        // console.log(data);
        var posts = {posts: data};
        $("#posts").append(myTemplate(posts));
        return true;
    })
    .then(function(result){
        goLookForDataAttributes();
    })
    .fail(function (reason) {
        if (reason !== '') {
            alert('Something went wrong:' + reason);
        }
    }); 

When we get the data back we append the items to our template:

.then(function(data){
    // console.log(data);
    var posts = {posts: data};
    $("#posts").append(myTemplate(posts));
    return true;
})

When everything is done we call another function in the other .then() branch:

   .then(function(result){
        goLookForDataAttributes();
    })

Promises can be chained. the second .then() is called after the first one is executed.

This is the last bit you need:

function goLookForDataAttributes()
{
    $('#posts li.item-handlebars').each(function (index, item) {
        $(item).addClass('big-font');
    });
}

This fiddle might help you.

In this example I parse the posts and add a class when handlebards has rendered the elements.

UPDATE:

Since you're calling a web api/web service, you can execute the promises in parallel, wait until the all the ajax requests have finished and execute your last method.

For the sake of simplicity I am going to create a fake promise (which should be your ajax request):

function buildPromise(id)
{
    var deferred = $.Deferred();

    setTimeout(function(){
        var data = {id: id, name: 'name: ' + id};
        deferred.resolve(data);
    }, 1000);

    return deferred.promise();
}

and I'll create an array of, let's say, 10 promises:

var promises = [];

for (var p = 0; p < 10; p++)
{
    promises.push(buildPromise(p));
}

Now I will be able to run all these promises in parallel:

$.when.apply($, promises)
    .then(function () {
        for(var i = 0; i < arguments.length; i++) {
            $('#content').append('<p>' + arguments[i].name + '</p>');
        }
    }).then(function(results) {
    return finalPromise();
})
.then(function(result){
    alert('success: ' + result.success);
    alert('Finished');
});

$.when.apply($, promises) resolves all the promises together, in parallel, and returns when we get back all the results.
The results can be found in arguments and can be read using the index of the array arguments[x].

When all the ajax requests have been executed we are going to call the finalPromise:

function finalPromise()
{
    var deferred = $.Deferred();

    setTimeout(function(){
        var data = { success: true };
        deferred.resolve(data);
    }, 1000);

    return deferred.promise();

}

finalPromise could be a regular function, with no promises, as well.

This is what it looks like.

Of course now you have to adapt it to your situation.

这篇关于jQuery的异步编程模式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆