gpt4 book ai didi

javascript - 如何在 Promise.then 中访问超出范围的变量(类似于闭包)

转载 作者:塔克拉玛干 更新时间:2023-11-02 20:53:35 25 4
gpt4 key购买 nike

难倒了这一点,确定有一种优雅的方法可以做到这一点,但不确定是什么。

我想要这样的东西:

let x = 5;

const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 2000);
}).then(() => {
console.log(x);
});

x = 3;
// Print out 5 after 2 seconds.

基本上,给定一个类似于上面的设置,有没有办法打印出 '5' 而不管 x 的值在异步超时期间是否改变?在我的例子中,很难在 resolve() 中简单地传递 x

最佳答案

您可以通过 IIFE 传递它:

let x = 5;

const p = (x => new Promise((resolve, reject) => {
// ^ use it here
setTimeout(() => {
resolve();
}, 2000);
}).then(() => {
console.log(x);
}))(x);
// ^ pass it here

x = 3;

之所以可行,是因为我们正在通过我们的函数创建一个范围,该函数将变量 x 作为其参数之一绑定(bind)到传递给 IIFE 的任何值。

这允许我们将全局 x 绑定(bind)到其他东西,但在 IIFE 中绑定(bind)的 x 不受影响。

由于我们在 IIFE 内部和外部都使用相同的名称,因此内部 x 也覆盖了外部。

也许使用不同的名称会使事情更具可读性:

let x = 5;

const p = (y => new Promise((resolve, reject) => {
// ^ use it here under a different name
setTimeout(() => {
resolve();
}, 2000);
}).then(() => {
console.log(y);
}))(x);
// ^ pass it here

x = 3;


注意:上面的工作是因为我们正在处理原始值,which in JavaScript are immutable因此每次重新分配都会重新创建一个新的。

var a = 'a'; 
var b = a; // this will bind `b` to the copy of value of `a`
a = 'changed'; // this won't affect `b`
console.log(a, b); // 'changed', 'a'

如果我们正在处理对象,使用 IIFE 是行不通的:

let x = { changed: false };

const p = (y => new Promise((resolve, reject) => {
// ^ still points to the same object as x
setTimeout(() => {
resolve();
}, 2000);
}).then(() => {
console.log(y);
}))(x);

x.changed = true; // this will affect y as well

原因是对象不是不可变的,因此每个绑定(bind)变量都指向同一个对象。

var a = { name: 'a' }; 
var b = a; // this will bind `b` to the value of `a` (not copy)
a.name = 'changed'; // this will also change `b`
console.log(a.name, b.name); // 'changed', 'changed'

为了用对象实现你需要的东西,你必须模仿 JS 引擎对原语的处理并克隆对象将其传递给 IIFE 时:

let x = {
changed: false
};

const p = (y => new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 2000);
}).then(() => {
console.log(y);
}))({ ...x });
// ^^^^^^^^ clone x when passing in

x.changed = true; // now this only affects the original, not the clone

或者使用Object.assign:

let x = {
changed: false
};

const p = (y => new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 2000);
}).then(() => {
console.log(y);
}))(Object.assign({}, x));
// ^^^^^^^^^^^^^^^^^^^ clone x when passing in

x.changed = true; // now this only affects the original, not the clone

注意:两者都是对象spreadObject.assign执行浅克隆。对于深度克隆,您可以 find many libraries on NPM .

参见:What is the most efficient way to deep clone an object in JavaScript?

对于大多数情况,这也可行:

let x = {
changed: false
};

const p = (y => new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 2000);
}).then(() => {
console.log(y);
}))(JSON.parse(JSON.stringify(x)));
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ clone x when passing in

x.changed = true; // now this only affects the original, not the clone


注意:使用 IIFE 只是一个简单的例子。常规函数也可以正常工作(但对于非原始值仍然存在相同的问题):

let x = 5;

const p = createPromise(x);

x = 3;

function createPromise(y) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 2000);
}).then(() => {
console.log(y);
})
}

关于javascript - 如何在 Promise.then 中访问超出范围的变量(类似于闭包),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54049706/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com