对象解构在 Promise 中解析和拒绝
Object destructuring resolve and reject in a Promise
对象解构不是我最喜欢的东西,我经常尽量避免使用它。但是在这种特殊情况下,我太好奇了,无法忽视正在发生的事情。
现在我们可以这样做了;
var o = {},
x = 1,
y = 2;
o = {x,y};
console.log(o); // <- {x: 1, y: 2}
一切都很好;
不过我的情况有点复杂;
var p = function(o){
o.promise = new Promise((resolve,reject) => o = {resolve,reject});
console.log(o) // -< {resolve: ƒ, reject: ƒ}
return o;
}({});
console.log(p); // -< {resolve: ƒ, reject: ƒ}
p
的 promise
属性 在哪里?所以我用经典的方式来做;
var q = function(o){
o.promise = new Promise((resolve,reject) => ( o.resolve = resolve
, o.reject = reject
));
console.log(o) // <- {promise: Promise, resolve: ƒ, reject: ƒ}
return o;
}({});
console.log(q); // <- {promise: Promise, resolve: ƒ, reject: ƒ}
我有一种奇怪的感觉,好像我错过了一些非常基本的东西,但我说不出来是什么。
您显示的任何代码都没有解构。
您正在将 o
重新分配给具有 2 个属性的简单普通新对象:
o = {resolve,reject}
这只是 ES2015 引入的 object literal shorthand syntax,与
相同
o = {resolve: resolve, reject: reject}
当然之前的 promise
属性 会丢失,因为它存在于一个不再被 o
引用的对象上(如果没有,最终将被垃圾收集内存中对它的其他引用)。
尝试
o.promise = new Promise((resolve,reject) => o = { ...o, resolve, reject });
不,...o
也不是解构,它是 object spread syntax。
您也可以使用
o.promise = new Promise((resolve,reject) => o = Object.assign(o, { resolve, reject }));
请注意 Object.assign()
触发设置器(如果有),而扩展语法则不会。
问题
让我用这个方便的图表解释发生了什么:
var p = function(o){
// 1 2 3
// v vvvvvvvvvvv vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
o.promise = new Promise((resolve,reject) => o = {resolve,reject});
// ^ ^ ^^^^^^^^^^^^^^^
// 6 5 4
console.log(o)
return o;
}({});
console.log(p);
- 对
o.promise
的赋值开始。 引擎将首先引用 o
,然后评估分配给 promise
属性 的内容。
- 赋值表达式是用
new
调用Promise
构造函数。引擎必须先评估整个事物并获得一个对象,然后再将任何事物分配给 promise
属性.
Promise
构造函数接收一个执行函数。该函数 立即被调用 。在执行者完成之前,promise 构造无法完成。
- 对于整个图片来说无关紧要,但为了清晰起见添加了 - 创建的对象具有两个属性
resolve
和 reject
。
- 对象已分配给
o
。请注意,第 1 步是作业的 start。任务还没有完成。这是中途。 代码 重新分配 o
在 o.promise
的分配完成之前。然而,这发生在引擎引用了分配给 o
的初始对象之后。 现在有两个与 o
相关的对象:
- 开始时第 1 步发生时分配的那个。
- 分配给它的那个现在 - 在第 5 步之后。
- (为简洁起见,压缩内容):执行程序功能已完成。
Promise
构造函数也已完成。已计算完整表达式 new Promise((resolve,reject) => o = {resolve,reject})
并生成一个值。 promise
属性 的赋值现在可以继续了。因为它使用来自步骤 1 的引用。代码分配给不再分配给 o
. 的对象的承诺值
- (未显示)在步骤 1 中分配给
o
的初始对象。没有更多的引用。它不符合垃圾回收条件,将从内存中消失。 (初分配)o
已死,万岁(新分配)o
.
整个情况可以用这段代码简化和表示:
//get two references to the same object
let o1 = {};
let o2 = o1;
o1.promise = (() => o1 = {resolve: "foo", reject: "bar"})();
console.log(o1);
console.log(o2);
由于 Promise
构造函数只是调用执行函数,因此它被一个 IIFE 所取代,该 IIFE 在对其主体进行评估时表现相同。 o1
和 o2
表示评估分配行的两个结果对象。由于 IIFE 重新分配了 o1
,o2
变量在那里向我们展示了初始对象发生了什么。它 确实 添加了 promise
属性 但(没有其他参考)它随后丢失了。
考虑到这一点,我们可以看到在原始代码中会发生类似的事情,如果我们有另一个对作为参数给出的对象的引用 o
:
//have a separate reference for the object passed below
const foo = {};
var p = function(o){
o.promise = new Promise((resolve,reject) => o = {resolve,reject});
console.log("o is", o)
return o;
}(foo);
console.log("p is", p);
//stack console shows `"promise": {}` but it's a promise object
//check the browser console if you want to see it
console.log("foo is", foo);
console.log("foo.promise is a Promise:", foo.promise instanceof Promise);
解决方案
connexo shows that you can use Object.assign()
in (收录于此以供参考):
var p = function(o){
o.promise = new Promise((resolve,reject) => o = Object.assign(o, { resolve, reject }));
console.log(o)
return o;
}({});
console.log(p);
//usage
p.promise
.then(result => console.log(`Completed with ${result}`));
p.resolve(42);
之所以有效,是因为 o
没有重新分配,而是使用更多属性进行了增强。这也是带有逗号运算符的版本有效的原因 - 它仍然没有重新分配 o
,只是修改它:
o.promise = new Promise((resolve,reject) => ( o.resolve = resolve
, o.reject = reject
));
另一种方法是对对象属性(而不是变量)使用解构赋值:
o.promise = new Promise((resolve,reject) => [o.resolve, o.reject] = [resolve, reject]);
或者如果你想要它更简洁:
o.promise = new Promise((...rs) => [o.resolve, o.reject] = rs);
var p = function(o){
o.promise = new Promise((...rs) => [o.resolve, o.reject] = rs);
console.log(o)
return o;
}({});
console.log(p);
//usage
p.promise
.then(result => console.log(`Completed with ${result}`));
p.resolve(42);
对象解构不是我最喜欢的东西,我经常尽量避免使用它。但是在这种特殊情况下,我太好奇了,无法忽视正在发生的事情。
现在我们可以这样做了;
var o = {},
x = 1,
y = 2;
o = {x,y};
console.log(o); // <- {x: 1, y: 2}
一切都很好;
不过我的情况有点复杂;
var p = function(o){
o.promise = new Promise((resolve,reject) => o = {resolve,reject});
console.log(o) // -< {resolve: ƒ, reject: ƒ}
return o;
}({});
console.log(p); // -< {resolve: ƒ, reject: ƒ}
p
的 promise
属性 在哪里?所以我用经典的方式来做;
var q = function(o){
o.promise = new Promise((resolve,reject) => ( o.resolve = resolve
, o.reject = reject
));
console.log(o) // <- {promise: Promise, resolve: ƒ, reject: ƒ}
return o;
}({});
console.log(q); // <- {promise: Promise, resolve: ƒ, reject: ƒ}
我有一种奇怪的感觉,好像我错过了一些非常基本的东西,但我说不出来是什么。
您显示的任何代码都没有解构。
您正在将 o
重新分配给具有 2 个属性的简单普通新对象:
o = {resolve,reject}
这只是 ES2015 引入的 object literal shorthand syntax,与
相同o = {resolve: resolve, reject: reject}
当然之前的 promise
属性 会丢失,因为它存在于一个不再被 o
引用的对象上(如果没有,最终将被垃圾收集内存中对它的其他引用)。
尝试
o.promise = new Promise((resolve,reject) => o = { ...o, resolve, reject });
不,...o
也不是解构,它是 object spread syntax。
您也可以使用
o.promise = new Promise((resolve,reject) => o = Object.assign(o, { resolve, reject }));
请注意 Object.assign()
触发设置器(如果有),而扩展语法则不会。
问题
让我用这个方便的图表解释发生了什么:
var p = function(o){
// 1 2 3
// v vvvvvvvvvvv vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
o.promise = new Promise((resolve,reject) => o = {resolve,reject});
// ^ ^ ^^^^^^^^^^^^^^^
// 6 5 4
console.log(o)
return o;
}({});
console.log(p);
- 对
o.promise
的赋值开始。 引擎将首先引用o
,然后评估分配给promise
属性 的内容。 - 赋值表达式是用
new
调用Promise
构造函数。引擎必须先评估整个事物并获得一个对象,然后再将任何事物分配给promise
属性. Promise
构造函数接收一个执行函数。该函数 立即被调用 。在执行者完成之前,promise 构造无法完成。- 对于整个图片来说无关紧要,但为了清晰起见添加了 - 创建的对象具有两个属性
resolve
和reject
。 - 对象已分配给
o
。请注意,第 1 步是作业的 start。任务还没有完成。这是中途。 代码 重新分配o
在o.promise
的分配完成之前。然而,这发生在引擎引用了分配给o
的初始对象之后。 现在有两个与o
相关的对象:- 开始时第 1 步发生时分配的那个。
- 分配给它的那个现在 - 在第 5 步之后。
- (为简洁起见,压缩内容):执行程序功能已完成。
Promise
构造函数也已完成。已计算完整表达式new Promise((resolve,reject) => o = {resolve,reject})
并生成一个值。promise
属性 的赋值现在可以继续了。因为它使用来自步骤 1 的引用。代码分配给不再分配给o
. 的对象的承诺值
- (未显示)在步骤 1 中分配给
o
的初始对象。没有更多的引用。它不符合垃圾回收条件,将从内存中消失。 (初分配)o
已死,万岁(新分配)o
.
整个情况可以用这段代码简化和表示:
//get two references to the same object
let o1 = {};
let o2 = o1;
o1.promise = (() => o1 = {resolve: "foo", reject: "bar"})();
console.log(o1);
console.log(o2);
由于 Promise
构造函数只是调用执行函数,因此它被一个 IIFE 所取代,该 IIFE 在对其主体进行评估时表现相同。 o1
和 o2
表示评估分配行的两个结果对象。由于 IIFE 重新分配了 o1
,o2
变量在那里向我们展示了初始对象发生了什么。它 确实 添加了 promise
属性 但(没有其他参考)它随后丢失了。
考虑到这一点,我们可以看到在原始代码中会发生类似的事情,如果我们有另一个对作为参数给出的对象的引用 o
:
//have a separate reference for the object passed below
const foo = {};
var p = function(o){
o.promise = new Promise((resolve,reject) => o = {resolve,reject});
console.log("o is", o)
return o;
}(foo);
console.log("p is", p);
//stack console shows `"promise": {}` but it's a promise object
//check the browser console if you want to see it
console.log("foo is", foo);
console.log("foo.promise is a Promise:", foo.promise instanceof Promise);
解决方案
connexo shows that you can use Object.assign()
in
var p = function(o){
o.promise = new Promise((resolve,reject) => o = Object.assign(o, { resolve, reject }));
console.log(o)
return o;
}({});
console.log(p);
//usage
p.promise
.then(result => console.log(`Completed with ${result}`));
p.resolve(42);
之所以有效,是因为 o
没有重新分配,而是使用更多属性进行了增强。这也是带有逗号运算符的版本有效的原因 - 它仍然没有重新分配 o
,只是修改它:
o.promise = new Promise((resolve,reject) => ( o.resolve = resolve
, o.reject = reject
));
另一种方法是对对象属性(而不是变量)使用解构赋值:
o.promise = new Promise((resolve,reject) => [o.resolve, o.reject] = [resolve, reject]);
或者如果你想要它更简洁:
o.promise = new Promise((...rs) => [o.resolve, o.reject] = rs);
var p = function(o){
o.promise = new Promise((...rs) => [o.resolve, o.reject] = rs);
console.log(o)
return o;
}({});
console.log(p);
//usage
p.promise
.then(result => console.log(`Completed with ${result}`));
p.resolve(42);