简体   繁体   English

Node.js - Promise 回调覆盖自定义对象

[英]Node.js - Promise callbacks override custom objects

This is my first post to this site, so I apologize in advance of any lack of data or tags, etc. I've been using this site for years, and it always helped me, but now I'm truly lost, and I couldn't find an answer anywhere.这是我第一次在这个网站上发帖,所以我提前为任何数据或标签等的缺失道歉。我已经使用这个网站多年了,它总是帮助我,但现在我真的迷路了,我在任何地方都找不到答案。

I have an application where I need to call a web service 10 times, each time with a different parameter.我有一个应用程序,我需要在其中调用 Web 服务 10 次,每次使用不同的参数。 The return payload is complex, so I created a custom object to hold the data.返回负载很复杂,因此我创建了一个自定义对象来保存数据。 I need data from all 10 calls before moving forward with my code, which led me to callback hell.在继续我的代码之前,我需要来自所有 10 个调用的数据,这导致我回调地狱。 I'm trying to use Promises to simplify this, but this is where I'm facing this weird issue.我正在尝试使用 Promises 来简化这一点,但这就是我面临这个奇怪问题的地方。 I'm able to replicate this issue with a simple class:我可以用一个简单的类来复制这个问题:

Custom Object (Person):自定义对象(人):

var person = {
  firstName : String,
  lastName : String,
  age : Number
}

function Person() { //getters and setters
} module.exports = Person;

Function getToken (returns a specific token my web service calls need), here replaced with a simple string:函数 getToken(返回我的 Web 服务调用需要的特定令牌),这里替换为一个简单的字符串:

function getToken() {

  return new Promise(function(resolve, reject) {
      var x = "random token";
      console.log('getting token');
      setTimeout(function(){resolve(x)}, 200);
    });
}

Function getAction: in my real app, it calls the web service.函数 getAction:在我的真实应用中,它调用 Web 服务。 Here it just creates a random person with an ID as input:这里它只是创建一个随机的人,输入一个 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);
  });
}

Function getActions: calls getAction for each input parameter.函数 getActions:为每个输入参数调用 getAction。 This function itself must return a Promise because there's another function waiting for all the data to be available before continuing.这个函数本身必须返回一个 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);});

  });
}

The output for this execution is:此执行的输出是:

---> Returning Person John 001
---> Returning Person John 002
---> Returning Person John 003
Person One: John 003
Person Two: John 003
Person Three: John 003

We can see that the getAction function was executed in the right order, with the right parameters.我们可以看到 getAction 函数以正确的顺序执行,并带有正确的参数。 But all 3 variables created in the getActions function have the value from the last execution.但是在 getActions 函数中创建的所有 3 个变量都具有上次执行的值。

I also tried this code:我也试过这个代码:

      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());

      });


And I got this output:我得到了这个输出:

---> 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

Finally, I tried using await, which generated even weirder results:最后,我尝试使用 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());


Result:结果:

---> 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

So the value is correct, until the callback for the next Promise, which replaces the value for all the variables.所以这个值是正确的,直到下一个 Promise 的回调,它替换了所有变量的值。 The behavior is the same if I create copies of the variable, even using JSON.parse(JSON.stringify()).如果我创建变量的副本,行为是相同的,即使使用 JSON.parse(JSON.stringify())。

This code works perfectly if I use strings instead of the Person object.如果我使用字符串而不是 Person 对象,则此代码可以完美运行。 However it would be extremely cumbersome to try and do this without custom objects.但是,在没有自定义对象的情况下尝试执行此操作将非常麻烦。

I'm sure that I am making some very basic mistake, but even though this seems to be very straightforward, I couldn't find anything on this particular issue anywhere.我确信我犯了一些非常基本的错误,但即使这看起来很简单,我在任何地方都找不到关于这个特定问题的任何内容。 This issue is happening with Node versions 9.5 and 10, running on MacOS (if it makes any difference).在 MacOS 上运行的 Node 版本 9.5 和 10 会发生此问题(如果有任何区别)。

Any help will be very much appreciated.任何帮助将不胜感激。 Thanks in advance!提前致谢!

Full code snippet:完整代码片段:

 // 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();

Without going too much into your code, I can already tell you that your Person 'class' methods are using person object declared at the top of the Person.js file.无需过多介绍您的代码,我已经可以告诉您,您的 Person“类”方法正在使用在Person.js文件顶部声明的person对象。 Fix those to use this and that should be it.修复那些使用这个和那个应该是它。

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

The way you have it set now the methods keep mutating the same object.您现在设置的方式会不断改变相同的对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM