函数在 .then() 承诺之前执行



GOAL:如果 html 元素的数量超过现有 JSON 文件的数组,则在 JSON 中创建数组。然后,获取每个数组的.length并添加到将附加到 html 的btn

我有一个脚本,它首先检测我的页面上有多少postWrapper元素,然后循环访问它们并确定commentslikesviews(存储三个外部 JSON 文件的三个变量)是否都有每个索引postWrapper元素的相应数组。如果数组在其中一个 JSON 文件中不存在,则postArray()函数会进行$.ajax调用,php 会将一个空数组写入每个 JSON 文件的末尾。然后,您将看到我使用.push([])向现有commentslikesviews变量添加一个空数组,以便它们也反映更新的 JSON 文件。

我正在使用.then()来确保其中一些功能是同步执行的。更新 JSON 文件并将空数组推送到现有 js 变量后,我需要借助我的injectBtn()函数将按钮附加到postWrapper元素。此函数读取commentslikesviews变量以确定数组的.length,然后根据需要添加计数。

我面临的问题是,如果这三个 JSON 文件中的一个没有足够的数组,postArray()函数似乎成功执行(因此 JSON 文件已更新),但获取.push([])方法的 js 变量在尝试执行和获取新创建的数组的.length之前不会更新injectBtn()。然后我留下以下错误:

jQuery.Deferred 异常:无法读取未定义的属性"include"错误:无法读取未定义的属性"include">

如何解决此问题,以便在injectBtn()尝试读取其中包含的数组.length之前更新我的 JSON 文件和commentslikesviews变量?

我的代码在下面(至少我认为相关的部分)。如果您有任何问题或需要更多背景信息,请告诉我。

var postArray = function() {
return $.ajax({
type: "post",
url: "/php/api.php",
dataType: "text",
data: {
array: "new"
}
});
}
var injectBtns = function(element, index) {
$(element[index]).append(
"<a class='js comment btn' href='#' title='Comment'>" +
"<span class='js comment count'>" + comments[index].length + "</span>" +
"<svg class='icon' width='16px' height='16px' viewbox='0 0 16 16'>" +
"<use xlink:href='/assets/icons.svg#comments'></use>" +
"</svg>" +
"</a>" +
"<a class='js like btn' href='#' title='Like'>" +
"<span class='js like count'>" + likes[index].length + "</span>" +
"<svg class='icon' width='16px' height='16px' viewbox='0 0 16 16'>" +
"<use xlink:href='/assets/icons.svg#likes'></use>" +
"</svg>" +
"</a>" +
"<a class='js view btn' href='#' title='Like'>" +
"<span class='js view count'>" + views[index].length + "</span>" +
"<svg class='icon' width='16px' height='16px' viewbox='0 0 16 16'>" +
"<use xlink:href='/assets/icons.svg#views'></use>" +
"</svg>" +
"</a>"
);
}
var postWrapper = $(".js.post.wrapper"),
commentBtn = ".js.comment.btn",
likeBtn = ".js.like.btn",
viewBtn = ".js.view.btn";
for (var i = 0; i < $(postWrapper).length; i++) {
(function(index) {
if (typeof comments[index] === "undefined" || typeof likes[index] === "undefined" || typeof views[index] === "undefined") {
postArray().then(function() {
comments.push([]);
likes.push([]);
views.push([]);
injectBtns(postWrapper, index);
});
} else {
injectBtns(postWrapper, index);
}
})(i);
if (comments[i].includes(client)) {
$(postWrapper[i]).children(commentBtn).addClass("active");
}
if (likes[i].includes(client)) {
$(postWrapper[i]).children(likeBtn).addClass("active");
$(postWrapper[i]).children(likeBtn).prop("title", "Unlike");
}
if (views[i].includes(client)) {
$(postWrapper[i]).children(viewBtn).addClass("active");
}
}

如何解决此问题,以便在 injectBtn() 尝试读取其中包含的数组的 .length 之前更新我的 JSON 文件和评论、喜欢和视图变量?

您还需要将它们放在then回调中。

for (var i = 0; i < $(postWrapper).length; i++) {
(function(i) {
var promise = (typeof comments[i] === "undefined" || typeof likes[i] === "undefined" || typeof views[i] === "undefined")
? postArray().then(function() {
comments.push([]);
likes.push([]);
views.push([]);
})
: $.when(undefined);
promise.then(function() {
injectBtns(postWrapper, i);
if (comments[i].includes(client)) {
$(postWrapper[i]).children(commentBtn).addClass("active");
}
if (likes[i].includes(client)) {
$(postWrapper[i]).children(likeBtn).addClass("active");
$(postWrapper[i]).children(likeBtn).prop("title", "Unlike");
}
if (views[i].includes(client)) {
$(postWrapper[i]).children(viewBtn).addClass("active");
}
});
})(i);
}

请注意,这整个方法非常糟糕

  • 为了防止竞争条件,您不仅应该请求"创建一个新数组(在最后)",而应该"在位置i处创建一个数组(如果它不存在)"。
  • 与其发出多个请求(每个缺少的数组一个请求),不如发出一个具有预期数组数(即postWrapper.length个)的简单请求。然后,php 脚本应根据需要生成尽可能多的脚本。
  • 您根本不应该为此使用客户端脚本,甚至不应该接受请求进行单独的评论/喜欢/查看部分(这是一个巨大的安全风险)。php 服务器应该知道哪个页面上有多少帖子,并首先为具有正确数量的数组提供 json。

最新更新