【问题标题】:Node.js - Promise callbacks override custom objectsNode.js - Promise 回调覆盖自定义对象
【发布时间】: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


【解决方案1】:

无需过多介绍您的代码,我已经可以告诉您,您的 Person 'class' 方法正在使用在 Person.js 顶部声明的 person 对象文件。修复那些使用 this 应该就是它了。

Person.prototype.setFirstName = function(firstName) { this.firstName = firstName; }

您现在设置它的方式,方法不断改变同一个对象。

【讨论】:

  • 谢谢!!我知道这很愚蠢。我必须将这些更改移动到我的主应用程序,但这解决了我正在运行的代码。我现在面临多级对象和“this.”的新问题,但我会弄清楚的。
猜你喜欢
  • 1970-01-01
  • 2013-05-24
  • 1970-01-01
  • 2016-07-24
  • 1970-01-01
  • 2014-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多