将函数转换为promise会改变看似无关的变量

时间:2017-06-13 14:38:13

标签: javascript promise

我目前正在完成编码挑战,并决定我希望更多的承诺练习,所以我将我的功能转换为承诺。这对第一个很好,但是当我添加第二个承诺时,我发现了一些我没想到的东西。这段代码:

// standard code provided for coding challenge
process.stdin.resume();
process.stdin.setEncoding('ascii');

var input_stdin = "";
var input_stdin_array = "";
var input_currentline = 0;

process.stdin.on('data', function (data) {
    input_stdin += data;
});

process.stdin.on('end', function () {
    input_stdin_array = input_stdin.split("\n");
    main();    
});

function readLine() {
    return input_stdin_array[input_currentline++];
}

function main() {
    var arr = [];
    for(arr_i = 0; arr_i < 6; arr_i++){
       arr[arr_i] = readLine().split(' ');
       arr[arr_i] = arr[arr_i].map(Number);
    }
    // My code
    let x = 0,
        y = 0,
        temp = 0,
        answer = 0;

    /* let incrementXY = new Promise((resolve, reject) => {
      if(x < arr[0].length - 2) {
        x += 1;
      } else {
        y += 1;
        x = 0;
      }
      setTimeout(function(){
        resolve(console.log("x is: " + x + " and y is: " + y));
      }, 250);
    });*/

    // function returns total of each hourglass shape
    let getHourGlass = new Promise((resolve, reject) => {
      for(j = 0; j <= 2; j++) {
        if(j === 0) {
          temp = arr[y][x]; 
        } else {
          temp += arr[y][x + j];
        }
        if(j === 1) {
          temp += arr[y + 1][x + 1];
        }
        temp += arr[y + 2][x + j];
      }
      setTimeout(function(){
        resolve(temp);
      }, 250);
    });

    getHourGlass.then(() => {   
      console.log("Temp is " + temp);
    });

记录临时变量的预期值7。

然而,当我取消注释incrementXY承诺代码时,即使我根本没有实现它,突然记录的temp的值从7变为4.鉴于该功能确实如此甚至没有引用temp变量,这怎么可能?此外,当我将incrementXY转换为函数时,只有当它被创建为一个承诺时才会发生这种情况。

如果它有用,那么当前输入是带有这些数据的2D数组:

1 1 1 0 0 0
0 1 0 0 0 0
1 1 1 0 0 0
0 0 2 4 4 0
0 0 0 2 0 0
0 0 1 2 4 0

我应该解释的另一件事是我使用的是HackerRank沙箱,所以它可能是他们环境的一些怪癖,但我的预感告诉我它可能是别的东西。

我可以转换承诺中的所有代码,但我认为这必须是使用承诺的某种怪癖,如果有人可以向我解释发生了什么,我会非常感激所以我可以感觉更自信,能够在将来正确使用它们而不会发生奇怪的事情。

1 个答案:

答案 0 :(得分:0)

回答这部分

  

然而,当我取消注释incrementXY承诺代码时,即使我根本没有实现它,突然记录的temp值从7变为4.鉴于函数不均匀参考temp变量,这怎么可能?

变量temp取决于在同一范围xy中定义的内容。传递给Promise构造函数的执行函数会更改影响temp值的变量。

let a = 0

const promise = new Promise(resolve => {
  console.log(`Creating a promise: ${a}`)
  a++
  
  setTimeout(resolve, 1000)
})

console.log(`Promise created: ${a}`)
a++
promise.then(() => console.log(`Promise resolved: ${a}`))

所以你的问题不是承诺本身,而是共享的可变状态。

  

所以我将我的功能转换为承诺

这没有多大意义。首先,我不明白为什么你的代码需要Promise。在您运行此代码时,您似乎拥有所有可用值。

然后Promises和Functions不可互换。可以认为Promise是一个,可以在以后的某个时间使用。它没有行动或操作的概念。它是执行函数,您将传递给执行所有脏工作的promise构造函数。

但如果你想玩承诺你可以做这样的事情

const delay = fn => timeout =>
  new Promise(resolve => setTimeout(() => resolve(fn()), timeout))

/* do not use shared mutable state 
let x = 0,
  y = 1,
  temp = 0;
  */
  

// promises are values (not functions)
const calculatingXY = delay(() => ({x: 1, y: 2}))(250)

calculatingXY.then(({x, y}) => console.log(`Value of x is ${x}, value of y is ${y}`))

// sum x and y after 500 ms timeout
const calculatingSum = calculatingXY
  .then(
    ({x, y}) => delay(() => x + y)(500)
  )

Promise.all([calculatingXY, calculatingSum])
  .then(
    ([{x,y}, z]) => console.log(`${x} + ${y} = ${z}`)
  )
  .catch(e => console.log(e))