为此感到困惑,请确保有一种优雅的方法来执行此操作,但不确定要执行什么操作。
我想要类似的东西:
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
的值在异步超时期间是否发生了变化?就我而言,很难在x
中传递resolve()
。
答案 0 :(得分:3)
您可以通过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
作为其参数之一绑定到传递给IIFE的任何值。
这使我们可以将全局x
绑定到其他对象,但是IIFE中限制的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
原因是对象不是不可变的,因此每个绑定变量都指向同一对象。
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
注意:对象spread和Object.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);
})
}
答案 1 :(得分:0)
是的,您可以使用工厂函数来生成您的promise,该promise可以用作变量的闭包。
function promiseFactory(x){
return new Promise(function(resolve){
setTimeout(function(){
console.log(x); // value as passed to factory call
resolve(x)
}, 1000)
});
}
let x = 5;
promiseFactory(x) // returns a promise which will always see x as 5
.then(function(x){console.log(x)})
一个小警告:这在这里起作用,因为x是一个整数,它是原始类型,因此将值复制过来。如果您使用的是引用类型,例如对象/数组,则必须传递克隆的对象