【问题标题】:Chaining function with then doesn't work correctly与 then 的链接功能无法正常工作
【发布时间】:2019-03-06 06:32:29
【问题描述】:
嘿,我遇到了一个问题,与 .then 链接的函数不能正常工作,而不是按应有的顺序工作。
我的代码:
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.3.1.min.js"></script>
<script>
var users = [];
var user = null;
function restCallA() {
return $.ajax({
url: "https://reqres.in/api/users?page=2",
type: "GET",
success: function(response) {
users = response.data;
console.log("users", users);
}
});
}
function restCallB() {
return $.ajax({
url: "https://reqres.in/api/users/2",
type: "GET",
success: function(response) {
user = response.data;
console.log("user", user);
}
});
}
function myFun(testArg) {
users.push(user);
console.log("why users is null?", testArg, users);
}
$(function() {
restCallA()
.then(restCallB)
.then(myFun("test"));
});
</script>
</body>
</html>
输出:
myFun 函数上的用户变量应该包含第一个 restCall 中的所有数据,并将第二个 restCall 中的数据推送到同一个变量。
变量确实获取了数据,但 myFun 函数在它们之前运行,因此其中的 users 变量为空。
结果图片:
我该如何解决这个问题?
【问题讨论】:
标签:
javascript
ajax
rest
promise
【解决方案1】:
.then 接受一个函数作为参数,但在
restCallA()
.then(restCallB)
.then(myFun("test"));
您正在调用 myFun,并将其返回值传递给第二个.then。它评估为:
restCallA()
.then(restCallB)
.then(undefined);
myFun立即运行,而解释器尝试将 Promise 链放在一起(在响应返回之前)。
传递一个调用 myFun 的函数:
restCallA()
.then(restCallB)
.then(() => myFun("test"));
您也可以使用.bind,它将创建一个带有所需参数的函数,但不会调用它:
restCallA()
.then(restCallB)
.then(myFun.bind(undefined, "test"));
var users = [];
var user = null;
function restCallA() {
return $.ajax({
url: "https://reqres.in/api/users?page=2",
type: "GET",
success: function(response) {
users = response.data;
console.log("users", users);
}
});
}
function restCallB() {
return $.ajax({
url: "https://reqres.in/api/users/2",
type: "GET",
success: function(response) {
user = response.data;
console.log("user", user);
}
});
}
function myFun(testArg) {
users.push(user);
console.log("why users is null?", testArg, users);
}
$(function() {
restCallA()
.then(restCallB)
.then(() => myFun("test"));
});
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.3.1.min.js"></script>
如果函数返回一个函数,则仅在.then的参数列表中调用一个函数,例如:
const fnThatReturnsFn = arg => resolveValue => console.log(arg, resolveValue);
someProm()
.then(fnThatReturnsFn('somearg'));
【解决方案2】:
$.ajax 返回一个类似 Promise 的对象。因此,通过在函数中的 then 中返回来自 ajax 调用的数据,利用它来发挥您的优势。
请注意,我已使用 @CertainPerformance's suggestions in their answer 之一来修复 myFun 问题。
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.3.1.min.js"></script>
<script>
function restCallA() {
return $.ajax({
url: "https://reqres.in/api/users?page=2",
type: "GET"
}).then(response => response.data);
}
function restCallB(users) {
return $.ajax({
url: "https://reqres.in/api/users/2",
type: "GET"
}).then(response => {
return {
// ES2015 method for adding a property named "users" with the value of the users variable
users,
user: response.data
};
});
}
function myFun(testArg, usersAndUser) {
usersAndUser.users.push(usersAndUser.user);
console.log(testArg);
}
$(function() {
restCallA()
.then(restCallB)
.then((usersAndUser) => myFun("test", usersAndUser));
});
</script>
</body>
</html>
请注意,我使用一个对象将users 和user 收集到一个对象中;您可以轻松地使用数组。