用另一个承诺履行(不解决)承诺
Fulfill (don't resolve) promise with another promise
我想用其他承诺来履行承诺。关键是我真的很想在第一个承诺完成后立即访问(仍在等待中的)第二个 promise。不幸的是,我似乎只能在两个承诺都实现后才能获得第二个承诺的分辨率值。
这是我想到的用例:
var picker = pickFile();
picker.then( // Wait for the user to pick a file.
function(downloadProgress) {
// The user picked a file. The file may not be available just yet (e.g.,
// if it has to be downloaded over the network) but we can already ask
// the user some more questions while the file is being obtained in the
// background.
...do some more user interaction...
return downloadProgress;
}
).then( // Wait for the download (if any) to complete.
function(file) {
// Do something with the file.
}
)
函数 pickFile
显示一个文件选择器,用户可以从中选择文件,从他们自己的硬盘驱动器或 URL。它 returns 承诺 picker
一旦用户选择了一个文件就会实现。此时,我们可能还是要通过网络下载选中的文件。因此,我无法将所选文件作为分辨率值来满足 picker
。相反,picker
应该用另一个承诺 downloadProgress
来实现,而这个承诺最终会用选定的文件来实现。
为了完整起见,这里是 pickFile
函数的模拟实现:
function pickFile() {
...display the file picker...
var resolveP1 = null;
var p1 = new Promise(
function(resolve, reject) {
resolveP1 = resolve;
}
);
// Mock code to pretend the user picked a file
window.setTimeout(function() {
var p2 = Promise.resolve('thefile');
resolveP1(p2); // <--- PROBLEM: I actually want to *fulfill* p1 with p2
}, 3000);
return p1;
}
标记行的问题是我想用新的承诺p2
履行承诺p1
,但我只知道如何解决它。 difference between fulfilling and resolving 是解析首先检查提供的值 p2
是否再次是一个承诺。如果是,则 p1
的实现将延迟到 p2
完成,然后 p1
将使用 p2
的分辨率值而不是 [=23= 来实现]本身。
我可以通过围绕 p2
构建一个包装器来解决这个问题,即通过替换行
resolveP1(p2); // <--- PROBLEM: I actually want to *fulfill* p1 with p2
来自
的第二个代码示例
resolveP1({promise: p2});
然后,在第一个代码示例中,我必须替换行
return downloadProgress;
来自
return downloadProgress.promise;
但是,当我真正想做的只是履行(而不是解决)一个承诺时,这似乎有点麻烦。
如果有任何建议,我将不胜感激。
除了我已经在问题中描述的解决方法之外,似乎没有其他解决方案。为了将来的参考,如果你想履行(而不是解决)一个承诺 p
与价值 val
,其中 val
是另一个承诺,那么只需调用承诺解决函数 [=带有参数 val
的 11=] 将无法按预期工作。它会导致 p
在 val
的状态下变为 "locked in",这样 p
将满足 val
的分辨率值一次 val
已实现(参见 spec)。
相反,将 val
包装在另一个对象中并用该对象解析 p
:
var resolveP; // Promise resolution function for p
var p = new Promise(
function(resolve, reject) {
resolveP = resolve;
}
);
function fulfillPwithPromise(val) { // Fulfills p with a promise val
resolveP({promise: val});
}
p.then(function(res) {
// Do something as soon as p is fulfilled...
return res.promise;
}).then(function(res) {
// Do something as soon as the second promise is fulfilled...
});
如果您已经知道 val
是一个承诺,则此解决方案有效。如果您不能对 val
的类型做出任何假设,那么您似乎不走运。您必须 始终 将承诺解析值包装在另一个对象中,或者您可以尝试检测 val
是否具有类型 "function" 的字段 then
并有条件地包装它。
也就是说,在某些情况下,promise 解析的默认行为实际上可能会产生预期的效果。因此,如果您确定要 fulfill 而不是 resolve 第一个承诺与第二个承诺,则仅使用上述解决方法。
尽管不同的人使用不同的术语,但在通用术语中,"fulfill" 表示将承诺置于 "success" 状态(与 "reject" 相对)——将要实现的状态然后触发 then
处理程序挂起它。
换句话说,您不能 "fulfill" 一个承诺一个承诺。你可以用一个值来实现它。 (顺便说一句,术语 "resolve" 通常表示满足或拒绝。)
您可以做的是 return 来自 .then
处理程序的承诺,这将产生实质上用 returned 承诺替换原始承诺的效果。
这是一个简单的例子:
asyncTask1 . then(asyncTask2) . then(processData)
其中 asyncTask1
是一个承诺,asyncTask2
是一个函数,return 是一个承诺。因此,当 asyncTask1
完成(成功完成)时,asyncTask2
运行,并且由 .then
编辑的承诺 return 由承诺 [=17] "taken over" =] returns,这样当它完成时,就可以处理数据了。
我可以通过使用承诺作为参数调用 Promise.resolve
来做类似的事情。这有点用词不当,因为我 不是 解决技术意义上的承诺。相反,创建的新promise是由我传入的promise"inhabited"。它也是没有用的,因为使用结果与使用我传入的promise完全相同:
Promise.resolve(asyncTask2)
与
的行为完全相同
asyncTask2
(假设 asyncTask2 已经是一个承诺;否则 Promise.resolve
具有创建一个承诺的效果,该承诺会立即用传入的值实现。)
正如您可以将承诺传递给 Promise.resolve
一样,您可以将承诺传递给作为承诺构造函数回调的参数提供给您的 resolve
函数。如果您传递给 resolve
的参数是非承诺,则该承诺会立即实现该值。但是,如果您传递给 resolve
的参数是另一个承诺,即您正在构建的承诺 "takes over the body" 的承诺。换句话说,您正在构建的承诺开始表现得与传递给 resolve
.
的承诺完全一样
"behave exactly" 我的意思是,如果您传递给 resolve
的承诺已经实现,那么您正在构建的承诺会立即以相同的价值实现。如果你传递给 resolve
的承诺已经被拒绝,你正在构建的承诺会立即被拒绝,原因相同。如果您传递给 resolve
的承诺尚未解决,那么当您传递给 resolve
的承诺是已解决。
正如令人困惑的是 Promise.resolve
可能会导致一个实际未解决的承诺,同样令人困惑的是调用传递给您的 resolve
函数作为承诺构造函数的参数如果您使用未解决的承诺调用它,可能 不会 实际解决正在构建的承诺。相反,正如我现在已经说过几次的那样,它的效果是使正在构建的承诺与传递给 resolve
.
的承诺完全一致。
因此,除非我遗漏了你问题的重点,否则 pickfile
可以写成
function pickFile() {
return new Promise(function(resolve, reject) {
...display the file picker...
// Mock code to pretend the user picked a file
window.setTimeout(function() {
resolve('thefile');
});
}
我不是很清楚你的问题,所以这可能不是你想要的。如果您愿意,请说明。
在从 Angular 的 $q 迁移到本机 Promise 功能的过程中找到了类似的解决方案。 Promise.all
可能是一个选项(在独立的并行异步任务的情况下)通过传递适当的 object 或用状态装饰的东西,在适当的时候将它传递给任何准备好的东西。在下面的 Promise.all 示例中,请注意它是如何在其中一个承诺中恢复的——我花了一段时间才意识到如何重定向链的结果。 all 的结果就是最后一个 promise 的 return。虽然这没有回答问题的标题,但使用 return Promise.reject(<an-object-including-a-promise>)
(或解析)提供了一系列 and/or 组异步任务共享访问和控制。在选择、下载然后处理文件的情况下,我将取出 progress-event 处理然后执行: pickFile.then(download,orFailGracefully)
和 downloadProgress
在 download
onResolve 处理程序中处理(download-progress 似乎不是异步任务)。下面是控制台中的相关实验。
var q = {
defer: function _defer(){
var deferred = { };
deferred.promise = new Promise(function(resolve, reject){
deferred.resolve = resolve;
deferred.reject = reject;
});
return deferred;
}
};
var communityThatCares = q.defer();
communityThatCares.promise.then(function(someGood){
console.log('someGood', someGood);
return someGood;
}, function(someBad){
console.warn('someBad', someBad);
return someBad;
});
(new Promise(function(resolve, reject){ communityThatCares.about = 'communityThatCares'; setTimeout(resolve,1000, communityThatCares); }))
.then(
function(e){
console.log(3,e); return e.resolve(e);
}, function(e){
console.warn(3, e); return e.reject(e);
});
var todo = {
find:'swan'
};
var greaterGood = [(
(new Promise(function(res,rej){ res(todo); })).then(function(e){ e.stuff = 'things'; return e; }),
(new Promise(function(res,reject){
reject(todo);
})).then(function(e){ return e; }
,function(e){
console.warn(1,e);
e.recover = 'uh oh';
return Promise.resolve(e);
}).then(function(e){ console.log(2,e); return e; }),
(new Promise(function(res,rej){ res(todo); })).then(function(e){ console.log(1,e); e.schedule = 'today'; return e; },function(e){ console.warn(1,e); return e; }).then(function(e){ console.log(2,e); return e; }))
];
var nkay = Promise.all( greaterGood )
.then(function(todo){
console.log('all',todo[0]); return todo;
}, function(todo){
console.warn('all',todo[0]); return todo;
});
我想用其他承诺来履行承诺。关键是我真的很想在第一个承诺完成后立即访问(仍在等待中的)第二个 promise。不幸的是,我似乎只能在两个承诺都实现后才能获得第二个承诺的分辨率值。
这是我想到的用例:
var picker = pickFile();
picker.then( // Wait for the user to pick a file.
function(downloadProgress) {
// The user picked a file. The file may not be available just yet (e.g.,
// if it has to be downloaded over the network) but we can already ask
// the user some more questions while the file is being obtained in the
// background.
...do some more user interaction...
return downloadProgress;
}
).then( // Wait for the download (if any) to complete.
function(file) {
// Do something with the file.
}
)
函数 pickFile
显示一个文件选择器,用户可以从中选择文件,从他们自己的硬盘驱动器或 URL。它 returns 承诺 picker
一旦用户选择了一个文件就会实现。此时,我们可能还是要通过网络下载选中的文件。因此,我无法将所选文件作为分辨率值来满足 picker
。相反,picker
应该用另一个承诺 downloadProgress
来实现,而这个承诺最终会用选定的文件来实现。
为了完整起见,这里是 pickFile
函数的模拟实现:
function pickFile() {
...display the file picker...
var resolveP1 = null;
var p1 = new Promise(
function(resolve, reject) {
resolveP1 = resolve;
}
);
// Mock code to pretend the user picked a file
window.setTimeout(function() {
var p2 = Promise.resolve('thefile');
resolveP1(p2); // <--- PROBLEM: I actually want to *fulfill* p1 with p2
}, 3000);
return p1;
}
标记行的问题是我想用新的承诺p2
履行承诺p1
,但我只知道如何解决它。 difference between fulfilling and resolving 是解析首先检查提供的值 p2
是否再次是一个承诺。如果是,则 p1
的实现将延迟到 p2
完成,然后 p1
将使用 p2
的分辨率值而不是 [=23= 来实现]本身。
我可以通过围绕 p2
构建一个包装器来解决这个问题,即通过替换行
resolveP1(p2); // <--- PROBLEM: I actually want to *fulfill* p1 with p2
来自
的第二个代码示例 resolveP1({promise: p2});
然后,在第一个代码示例中,我必须替换行
return downloadProgress;
来自
return downloadProgress.promise;
但是,当我真正想做的只是履行(而不是解决)一个承诺时,这似乎有点麻烦。
如果有任何建议,我将不胜感激。
除了我已经在问题中描述的解决方法之外,似乎没有其他解决方案。为了将来的参考,如果你想履行(而不是解决)一个承诺 p
与价值 val
,其中 val
是另一个承诺,那么只需调用承诺解决函数 [=带有参数 val
的 11=] 将无法按预期工作。它会导致 p
在 val
的状态下变为 "locked in",这样 p
将满足 val
的分辨率值一次 val
已实现(参见 spec)。
相反,将 val
包装在另一个对象中并用该对象解析 p
:
var resolveP; // Promise resolution function for p
var p = new Promise(
function(resolve, reject) {
resolveP = resolve;
}
);
function fulfillPwithPromise(val) { // Fulfills p with a promise val
resolveP({promise: val});
}
p.then(function(res) {
// Do something as soon as p is fulfilled...
return res.promise;
}).then(function(res) {
// Do something as soon as the second promise is fulfilled...
});
如果您已经知道 val
是一个承诺,则此解决方案有效。如果您不能对 val
的类型做出任何假设,那么您似乎不走运。您必须 始终 将承诺解析值包装在另一个对象中,或者您可以尝试检测 val
是否具有类型 "function" 的字段 then
并有条件地包装它。
也就是说,在某些情况下,promise 解析的默认行为实际上可能会产生预期的效果。因此,如果您确定要 fulfill 而不是 resolve 第一个承诺与第二个承诺,则仅使用上述解决方法。
尽管不同的人使用不同的术语,但在通用术语中,"fulfill" 表示将承诺置于 "success" 状态(与 "reject" 相对)——将要实现的状态然后触发 then
处理程序挂起它。
换句话说,您不能 "fulfill" 一个承诺一个承诺。你可以用一个值来实现它。 (顺便说一句,术语 "resolve" 通常表示满足或拒绝。)
您可以做的是 return 来自 .then
处理程序的承诺,这将产生实质上用 returned 承诺替换原始承诺的效果。
这是一个简单的例子:
asyncTask1 . then(asyncTask2) . then(processData)
其中 asyncTask1
是一个承诺,asyncTask2
是一个函数,return 是一个承诺。因此,当 asyncTask1
完成(成功完成)时,asyncTask2
运行,并且由 .then
编辑的承诺 return 由承诺 [=17] "taken over" =] returns,这样当它完成时,就可以处理数据了。
我可以通过使用承诺作为参数调用 Promise.resolve
来做类似的事情。这有点用词不当,因为我 不是 解决技术意义上的承诺。相反,创建的新promise是由我传入的promise"inhabited"。它也是没有用的,因为使用结果与使用我传入的promise完全相同:
Promise.resolve(asyncTask2)
与
的行为完全相同asyncTask2
(假设 asyncTask2 已经是一个承诺;否则 Promise.resolve
具有创建一个承诺的效果,该承诺会立即用传入的值实现。)
正如您可以将承诺传递给 Promise.resolve
一样,您可以将承诺传递给作为承诺构造函数回调的参数提供给您的 resolve
函数。如果您传递给 resolve
的参数是非承诺,则该承诺会立即实现该值。但是,如果您传递给 resolve
的参数是另一个承诺,即您正在构建的承诺 "takes over the body" 的承诺。换句话说,您正在构建的承诺开始表现得与传递给 resolve
.
"behave exactly" 我的意思是,如果您传递给 resolve
的承诺已经实现,那么您正在构建的承诺会立即以相同的价值实现。如果你传递给 resolve
的承诺已经被拒绝,你正在构建的承诺会立即被拒绝,原因相同。如果您传递给 resolve
的承诺尚未解决,那么当您传递给 resolve
的承诺是已解决。
正如令人困惑的是 Promise.resolve
可能会导致一个实际未解决的承诺,同样令人困惑的是调用传递给您的 resolve
函数作为承诺构造函数的参数如果您使用未解决的承诺调用它,可能 不会 实际解决正在构建的承诺。相反,正如我现在已经说过几次的那样,它的效果是使正在构建的承诺与传递给 resolve
.
因此,除非我遗漏了你问题的重点,否则 pickfile
可以写成
function pickFile() {
return new Promise(function(resolve, reject) {
...display the file picker...
// Mock code to pretend the user picked a file
window.setTimeout(function() {
resolve('thefile');
});
}
我不是很清楚你的问题,所以这可能不是你想要的。如果您愿意,请说明。
在从 Angular 的 $q 迁移到本机 Promise 功能的过程中找到了类似的解决方案。 Promise.all
可能是一个选项(在独立的并行异步任务的情况下)通过传递适当的 object 或用状态装饰的东西,在适当的时候将它传递给任何准备好的东西。在下面的 Promise.all 示例中,请注意它是如何在其中一个承诺中恢复的——我花了一段时间才意识到如何重定向链的结果。 all 的结果就是最后一个 promise 的 return。虽然这没有回答问题的标题,但使用 return Promise.reject(<an-object-including-a-promise>)
(或解析)提供了一系列 and/or 组异步任务共享访问和控制。在选择、下载然后处理文件的情况下,我将取出 progress-event 处理然后执行: pickFile.then(download,orFailGracefully)
和 downloadProgress
在 download
onResolve 处理程序中处理(download-progress 似乎不是异步任务)。下面是控制台中的相关实验。
var q = {
defer: function _defer(){
var deferred = { };
deferred.promise = new Promise(function(resolve, reject){
deferred.resolve = resolve;
deferred.reject = reject;
});
return deferred;
}
};
var communityThatCares = q.defer();
communityThatCares.promise.then(function(someGood){
console.log('someGood', someGood);
return someGood;
}, function(someBad){
console.warn('someBad', someBad);
return someBad;
});
(new Promise(function(resolve, reject){ communityThatCares.about = 'communityThatCares'; setTimeout(resolve,1000, communityThatCares); }))
.then(
function(e){
console.log(3,e); return e.resolve(e);
}, function(e){
console.warn(3, e); return e.reject(e);
});
var todo = {
find:'swan'
};
var greaterGood = [(
(new Promise(function(res,rej){ res(todo); })).then(function(e){ e.stuff = 'things'; return e; }),
(new Promise(function(res,reject){
reject(todo);
})).then(function(e){ return e; }
,function(e){
console.warn(1,e);
e.recover = 'uh oh';
return Promise.resolve(e);
}).then(function(e){ console.log(2,e); return e; }),
(new Promise(function(res,rej){ res(todo); })).then(function(e){ console.log(1,e); e.schedule = 'today'; return e; },function(e){ console.warn(1,e); return e; }).then(function(e){ console.log(2,e); return e; }))
];
var nkay = Promise.all( greaterGood )
.then(function(todo){
console.log('all',todo[0]); return todo;
}, function(todo){
console.warn('all',todo[0]); return todo;
});