jQuery 异步编程模式?
jQuery Asynchronous programming pattern?
我继承了一个扫描页面以查找数据属性并相应地修改 dom、添加处理程序等的应用程序。
我被要求实现动态标记,由此我发出一个 ajax 调用以获取 json 数据,然后使用 Handlebars 根据返回的数据呈现新的 html。
我需要告诉主要的外部应用程序等到所有 json 调用都已解决,然后再去寻找数据属性。
我应该采用哪种模式来执行此操作?
非常感谢任何帮助。
谢谢,
斯科特
更新
outer.js - 扫描 DOM 寻找要做的事情。
inner.js - 发出 0-9 ajax 调用(取决于我所在的页面)。每个 ajax 调用都有一个 .then() 函数调用 Handlebars 函数来编写标记。
如果我只有一个 ajax 调用,我可以将 inner.js 作为延迟传回给 outer.js。然后,在 ajax 的 .then() 函数中,我将调用 inner.js.resolve().
但是如果我对 9 个可能的每一个都这样做,inner.js 将在 #1 运行之后但在#2 完成之前解决。
如何动态设置 outer.js 用于等待它们全部解决的延迟数?
像这样延迟绑定数组似乎是不可能的:
在 inner.js 的顶部:
var application = jQuery.Deferred();
var arrayOfAsync = [];
application.done(arrayOfAsync);
然后,当在页面上找到 jQuery 个选择器时,我可以执行
arrayOfAsync.push(localPromise);
但这似乎不起作用……应该吗?这将假设 Deferred() 实际上只是保留一个普通数组,它可能不是...
在这种情况下你应该使用 promises。
假设您有 车把 模板:
<script id="PostsTempl" type="text/x-handlebars-template">
{{#each posts}}
<li class="item-handlebars">{{body}}</li>
{{/each}}
</script>
其中应填充从网络 api/web 服务获取的一系列帖子。
您将在使用前编译模板:
var myTemplate = Handlebars.compile($("#PostsTempl").html());
现在我们需要一个函数来调用 Web api/web 服务并获取一些数据:
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();
}
我们将使用 $.ajax
来 GET 数据。我们在这里定义了一个promise:
var deferred = $.Deferred();
这将在我们取回数据时解决:
success: function (jsonData) {
if (jsonData) {
deferred.resolve(jsonData);
} else {
deferred.reject('');
}
},
或者如果没有数据,最终会被拒绝。
return deferred.promise();
会 return 我们的承诺。
现在我们可以调用解析 promise 并反馈一些数据的函数:
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);
}
});
当我们取回数据时,我们将这些项目附加到我们的模板中:
.then(function(data){
// console.log(data);
var posts = {posts: data};
$("#posts").append(myTemplate(posts));
return true;
})
当一切都完成后,我们在另一个 .then()
分支中调用另一个函数:
.then(function(result){
goLookForDataAttributes();
})
Promise 可以链接。
第二个 .then()
在第一个执行后被调用。
这是您需要的最后一点:
function goLookForDataAttributes()
{
$('#posts li.item-handlebars').each(function (index, item) {
$(item).addClass('big-font');
});
}
这篇 fiddle 可能会对您有所帮助。
在这个例子中,我解析帖子并在 handlebards 呈现元素时添加 class。
更新:
由于您正在调用 Web api/web 服务,因此您可以并行执行承诺,等待所有 ajax 请求完成并执行您的最后一个方法。
为了简单起见,我将创建一个虚假的承诺(应该是您的 ajax 请求):
function buildPromise(id)
{
var deferred = $.Deferred();
setTimeout(function(){
var data = {id: id, name: 'name: ' + id};
deferred.resolve(data);
}, 1000);
return deferred.promise();
}
然后我将创建一个包含 10 个承诺的数组:
var promises = [];
for (var p = 0; p < 10; p++)
{
promises.push(buildPromise(p));
}
现在我将能够运行并行实现所有这些承诺:
$.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)
并行解决所有承诺,并在我们取回所有结果时 returns。
结果可以在 arguments
中找到,可以使用数组的索引 arguments[x]
.
读取
当所有 ajax 请求都已执行后,我们将调用 finalPromise
:
function finalPromise()
{
var deferred = $.Deferred();
setTimeout(function(){
var data = { success: true };
deferred.resolve(data);
}, 1000);
return deferred.promise();
}
finalPromise
也可以是一个没有承诺的常规函数。
This就是这个样子
当然现在你得根据自己的情况进行调整了。
我继承了一个扫描页面以查找数据属性并相应地修改 dom、添加处理程序等的应用程序。
我被要求实现动态标记,由此我发出一个 ajax 调用以获取 json 数据,然后使用 Handlebars 根据返回的数据呈现新的 html。
我需要告诉主要的外部应用程序等到所有 json 调用都已解决,然后再去寻找数据属性。
我应该采用哪种模式来执行此操作?
非常感谢任何帮助。
谢谢, 斯科特
更新
outer.js - 扫描 DOM 寻找要做的事情。
inner.js - 发出 0-9 ajax 调用(取决于我所在的页面)。每个 ajax 调用都有一个 .then() 函数调用 Handlebars 函数来编写标记。
如果我只有一个 ajax 调用,我可以将 inner.js 作为延迟传回给 outer.js。然后,在 ajax 的 .then() 函数中,我将调用 inner.js.resolve().
但是如果我对 9 个可能的每一个都这样做,inner.js 将在 #1 运行之后但在#2 完成之前解决。
如何动态设置 outer.js 用于等待它们全部解决的延迟数?
像这样延迟绑定数组似乎是不可能的:
在 inner.js 的顶部:
var application = jQuery.Deferred();
var arrayOfAsync = [];
application.done(arrayOfAsync);
然后,当在页面上找到 jQuery 个选择器时,我可以执行
arrayOfAsync.push(localPromise);
但这似乎不起作用……应该吗?这将假设 Deferred() 实际上只是保留一个普通数组,它可能不是...
在这种情况下你应该使用 promises。
假设您有 车把 模板:
<script id="PostsTempl" type="text/x-handlebars-template">
{{#each posts}}
<li class="item-handlebars">{{body}}</li>
{{/each}}
</script>
其中应填充从网络 api/web 服务获取的一系列帖子。
您将在使用前编译模板:
var myTemplate = Handlebars.compile($("#PostsTempl").html());
现在我们需要一个函数来调用 Web api/web 服务并获取一些数据:
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();
}
我们将使用 $.ajax
来 GET 数据。我们在这里定义了一个promise:
var deferred = $.Deferred();
这将在我们取回数据时解决:
success: function (jsonData) {
if (jsonData) {
deferred.resolve(jsonData);
} else {
deferred.reject('');
}
},
或者如果没有数据,最终会被拒绝。
return deferred.promise();
会 return 我们的承诺。
现在我们可以调用解析 promise 并反馈一些数据的函数:
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);
}
});
当我们取回数据时,我们将这些项目附加到我们的模板中:
.then(function(data){
// console.log(data);
var posts = {posts: data};
$("#posts").append(myTemplate(posts));
return true;
})
当一切都完成后,我们在另一个 .then()
分支中调用另一个函数:
.then(function(result){
goLookForDataAttributes();
})
Promise 可以链接。
第二个 .then()
在第一个执行后被调用。
这是您需要的最后一点:
function goLookForDataAttributes()
{
$('#posts li.item-handlebars').each(function (index, item) {
$(item).addClass('big-font');
});
}
这篇 fiddle 可能会对您有所帮助。
在这个例子中,我解析帖子并在 handlebards 呈现元素时添加 class。
更新:
由于您正在调用 Web api/web 服务,因此您可以并行执行承诺,等待所有 ajax 请求完成并执行您的最后一个方法。
为了简单起见,我将创建一个虚假的承诺(应该是您的 ajax 请求):
function buildPromise(id)
{
var deferred = $.Deferred();
setTimeout(function(){
var data = {id: id, name: 'name: ' + id};
deferred.resolve(data);
}, 1000);
return deferred.promise();
}
然后我将创建一个包含 10 个承诺的数组:
var promises = [];
for (var p = 0; p < 10; p++)
{
promises.push(buildPromise(p));
}
现在我将能够运行并行实现所有这些承诺:
$.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)
并行解决所有承诺,并在我们取回所有结果时 returns。
结果可以在 arguments
中找到,可以使用数组的索引 arguments[x]
.
当所有 ajax 请求都已执行后,我们将调用 finalPromise
:
function finalPromise()
{
var deferred = $.Deferred();
setTimeout(function(){
var data = { success: true };
deferred.resolve(data);
}, 1000);
return deferred.promise();
}
finalPromise
也可以是一个没有承诺的常规函数。
This就是这个样子
当然现在你得根据自己的情况进行调整了。