Promise 的参数在异步调用后会发生变化的坑

Promise 的参数在异步调用后会发生变化的坑

在前端开发中,异步编程是必不可少的一部分。而 Promise 作为实现异步编程的一种方式,被广泛使用。然而,在使用 Promise 进行异步编程时,我们需要注意一个坑点,那就是 Promise 的参数在异步调用后会发生变化。

这个问题的根源在于 JavaScript 中的变量作用域和引用传递。当我们在 Promise 中传入一个参数并在异步调用中对其进行修改时,由于 JavaScript 中的引用传递,Promise 外部的参数也会发生相应的变化。这可能会导致一些不可预料的结果,特别是在多个 Promise 嵌套调用的情况下。

下面来看一个示例代码:

let data = {id: 1, name: '张三'};

function fetchData(data) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      data.name = '李四';
      resolve(data);
    }, 1000);
  });
}

fetchData(data)
  .then(data => {
    console.log('第一次调用:', data);
    return fetchData(data);
  })
  .then(data => {
    console.log('第二次调用:', data);
  });

console.log('原始数据:', data);

在上面的代码中,我们定义了一个 data 变量,并将其传入 fetchData 方法中。在 fetchData 方法中,我们使用了一个定时器模拟异步操作,并在异步操作完成后修改了传入的参数 dataname 属性。在 Promise 的 then 方法中,我们又连续两次调用了 fetchData 方法,并在每次调用后打印出返回的 data 参数。最后,我们在 Promise 外部打印了一次原始数据 data

接下来看一下运行结果:

可以看到,虽然我们在 Promise 外部打印的原始数据 dataname 属性仍然是 "张三",但在 Promise 内部,我们已经将其修改为了 "李四"。而且,在第二次调用 fetchData 方法时,我们传入的参数 data 已经是被修改过的了。

这个问题的解决方法很简单,我们只需要在 Promise 内部对传入的参数进行复制,而不是直接对其进行修改即可。修改后的代码如下:

let data = {id: 1, name: '张三'};

function fetchData(data) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      let newData = {...data}; // 复制传入的参数
      newData.name = '李四';
      resolve(newData);
    }, 1000);
  });
}

fetchData(data)
  .then(data => {
    console.log('第一次调用:', data);
    return fetchData(data);
  })
  .then(data => {
    console.log('第二次调用:', data);
  });

console.log('原始数据:', data);

这样修改后,我们就可以在异步调用中对参数进行修改,而不会影响到 Promise 外部的参数了。

总结一下,当我们使用 Promise 进行异步编程时,需要注意其参数在异步调用后可能会发生变化的问题。为了避免这个问题,我们可以在 Promise 内部对传入的参数进行复制,而不是直接对其进行修改。这个问题虽然看起来很小,但在实际开发中可能会造成一些难以预料的问题,因此需要引起我们的重视。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65bcd9bfadd4f0e0ff6487b4