【发布时间】:2019-11-16 06:01:35
【问题描述】:
这是我第一次在这个网站上发帖,所以我提前为任何缺乏数据或标签等道歉。我已经使用这个网站多年了,它总是对我有帮助,但现在我真的迷路了,我在任何地方都找不到答案。
我有一个应用程序,我需要调用一个 Web 服务 10 次,每次都使用不同的参数。返回的有效负载很复杂,因此我创建了一个自定义对象来保存数据。在继续编写代码之前,我需要所有 10 个调用的数据,这导致我陷入回调地狱。我正在尝试使用 Promises 来简化这一点,但这就是我面临这个奇怪问题的地方。我可以用一个简单的类来复制这个问题:
自定义对象(人):
var person = {
firstName : String,
lastName : String,
age : Number
}
function Person() { //getters and setters
} module.exports = Person;
函数getToken(返回我的网络服务调用需要的特定令牌),这里替换为一个简单的字符串:
function getToken() {
return new Promise(function(resolve, reject) {
var x = "random token";
console.log('getting token');
setTimeout(function(){resolve(x)}, 200);
});
}
函数getAction:在我的真实应用中,它调用网络服务。在这里,它只是创建了一个带有 ID 作为输入的随机人:
function getAction(uuid) {
return new Promise(resolve => {
var newPerson = new Person();
newPerson.setFirstName("John " + uuid);
newPerson.setLastName("Doe");
newPerson.setAge(20);
console.log("---> Returning Person " + newPerson.getFirstName());
setTimeout(function(){resolve(newPerson)}, 300);
});
}
函数getActions:为每个输入参数调用getAction。这个函数本身必须返回一个 Promise,因为在继续之前还有另一个函数在等待所有数据可用。
function getActions() {
return new Promise(function(resolve, reject) {
getToken().then(async function(tokenret) {
var userIds = ["001", "002", "003", "004", "005", "006", "007", "008", "009", "010" ];
var myPromise = Promise.join;
myPromise(getAction(userIds[0]), getAction(userIds[1]), getAction(userIds[2]), function(personOne, personTwo, personThree) {
console.log("Person One: " + personOne.getFirstName());
console.log("Person Two: " + personTwo.getFirstName());
console.log("Person Three: " + personThree.getFirstName());
});
}).catch(function(rej) {console.log("Promise Failed! " + rej);});
});
}
这次执行的输出是:
---> Returning Person John 001
---> Returning Person John 002
---> Returning Person John 003
Person One: John 003
Person Two: John 003
Person Three: John 003
我们可以看到 getAction 函数以正确的顺序执行,并带有正确的参数。但是在 getActions 函数中创建的所有 3 个变量都具有上次执行的值。
我也试过这个代码:
const allPromises = userIds.map(userIds => getAction(userIds));
await Promise.all(allPromises).then(function(allResults) {
console.log("Received " + allResults.length + " records");
var thisPersonZero = allResults[0];
console.log("This person 0: " + thisPersonZero.getFirstName());
var thisPersonOne = allResults[1];
console.log("This person 1 " + + thisPersonOne.getFirstName());
var thisPersonTwo = allResults[2];
console.log("This person 2 " + + thisPersonTwo.getFirstName());
console.log("Recapping");
console.log("This person 0: " + thisPersonZero.getFirstName());
console.log("This person 1: " + thisPersonOne.getFirstName());
console.log("This person 2: " + thisPersonTwo.getFirstName());
});
我得到了这个输出:
---> Returning Person John 001
---> Returning Person John 002
---> Returning Person John 003
---> Returning Person John 004
---> Returning Person John 005
---> Returning Person John 006
---> Returning Person John 007
---> Returning Person John 008
---> Returning Person John 009
---> Returning Person John 010
Received 10 records
This person 0: John 010
This person 1 John 010
This person 2 John 010
Recapping
This person 0: John 010
This person 1: John 010
This person 2: John 010
最后,我尝试使用 await,结果更奇怪:
var firstPerson = await getAction(userIds[0]);
console.log("First Person: " + firstPerson.getFirstName());
var secondPerson = await getAction(userIds[1]);
console.log("Second Person: " + secondPerson.getFirstName());
console.log("Recapping");
console.log("First Person: " + firstPerson.getFirstName());
console.log("Second Person: " + secondPerson.getFirstName());
结果:
---> Returning Person John 001
First Person: John 001
---> Returning Person John 002
Second Person: John 002
Recapping
First Person: John 002
Second Person: John 002
所以值是正确的,直到下一个 Promise 的回调,它替换所有变量的值。如果我创建变量的副本,即使使用 JSON.parse(JSON.stringify()),行为也是一样的。
如果我使用字符串而不是 Person 对象,则此代码可以完美运行。但是,在没有自定义对象的情况下尝试这样做会非常麻烦。
我确信我犯了一些非常基本的错误,但即使这看起来很简单,我在任何地方都找不到关于这个特定问题的任何信息。在 MacOS 上运行的 Node 版本 9.5 和 10 会出现此问题(如果有任何不同)。
任何帮助将不胜感激。提前致谢!
完整代码sn-p:
// Person.js
var person = {
firstName : String,
lastName : String,
age : Number
}
function Person() {
Person.prototype.setFirstName = function(firstName) { person.firstName = firstName; }
Person.prototype.setLastName = function(lastName) { person.lastName = lastName; }
Person.prototype.setAge = function(age) { person.age = age; }
Person.prototype.getFirstName = function() { return (typeof person.firstName === 'undefined') ? '' : person.firstName; }
Person.prototype.getLastName = function() { return (typeof person.lastName === 'undefined') ? '' : person.lastName; }
Person.prototype.getAge = function() { return (typeof person.age === 'undefined') ? 0 : person.age; }
}
module.exports = Person;
// Error.js
var Promise = require('bluebird');
var Person = require("./models/Person");
function getToken() {
return new Promise(function(resolve, reject) {
var x = "random token";
console.log('getting token');
setTimeout(function(){resolve(x)}, 200);
});
}
function getActions() {
return new Promise(function(resolve, reject) {
getToken().then(async function(tokenret) {
var userIds = ["001", "002", "003", "004", "005", "006", "007", "008", "009", "010" ];
/*
var myPromise = Promise.join;
myPromise(getAction(userIds[0]), getAction(userIds[1]), getAction(userIds[2]), function(personOne, personTwo, personThree) {
console.log("Person One: " + personOne.getFirstName());
console.log("Person Two: " + personTwo.getFirstName());
console.log("Person Three: " + personThree.getFirstName());
});
*/
var firstPerson = await getAction(userIds[0]);
console.log("First Person: " + firstPerson.getFirstName());
var secondPerson = await getAction(userIds[1]);
console.log("Second Person: " + secondPerson.getFirstName());
console.log("Recapping");
console.log("First Person: " + firstPerson.getFirstName());
console.log("Second Person: " + secondPerson.getFirstName());
/*
const allPromises = userIds.map(userIds => getAction(userIds));
await Promise.all(allPromises).then(function(allResults) {
for (var x = 0; x < allResults.length; x++)
{
var thisPerson = allResults[x];
console.log("This Person: " + thisPerson.getFirstName());
}
console.log("Received " + allResults.length + " records");
var thisPersonZero = allResults[0];
console.log("This person 0: " + thisPersonZero.getFirstName());
var thisPersonOne = allResults[1];
console.log("This person 1 " + thisPersonOne.getFirstName());
var thisPersonTwo = allResults[2];
console.log("This person 2 " + thisPersonTwo.getFirstName());
console.log("Recapping");
console.log("This person 0: " + thisPersonZero.getFirstName());
console.log("This person 1: " + thisPersonOne.getFirstName());
console.log("This person 2: " + thisPersonTwo.getFirstName());
});
*/
}).catch(function(rej) {console.log("Promise Failed! " + rej);});
});
}
function getAction(uuid) {
return new Promise(resolve => {
var newPerson = new Person();
newPerson.setFirstName("John " + uuid);
newPerson.setLastName("Doe");
newPerson.setAge(20);
console.log("---> Returning Person " + newPerson.getFirstName());
setTimeout(function(){resolve(newPerson)}, 300);
});
}
getActions();
【问题讨论】:
-
只有一个
person对象?你期待什么? -
尝试在有问题的地方制作小样本,读起来很难。
-
抱歉,我认为这有点过分了,但我读过很多其他帖子,人们抱怨的恰恰相反——没有足够的代码,没有足够的上下文......
标签: javascript arrays node.js promise