[英]Fulfill (don't resolve) promise with another 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中选择文件。 它返回一个诺言picker
,该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
,但是我只知道如何解决它。 满足与解决之间的区别在于 ,解决首先检查提供的值p2
是否再次是一个承诺。 如果是,则将p1
实现推迟到p2
满足,然后使用p2
的分辨率值而不是p2
本身来实现p1
。
我可以通过围绕p2
构建包装器来解决此问题,即替换行
resolveP1(p2); // <--- PROBLEM: I actually want to *fulfill* p1 with p2
从第二个代码示例
resolveP1({promise: p2});
然后,在第一个代码示例中,我将不得不替换该行
return downloadProgress;
通过
return downloadProgress.promise;
但是,当我真正想做的只是兑现(而不是解决)承诺时,这似乎有点不合时宜。
我将不胜感激任何建议。
除了我已经在问题中描述的解决方法之外,似乎没有其他解决方案。 供将来参考,如果您想实现(而不是解决)带有值val
的promise p
,其中val
是另一个promise,那么仅使用参数val
调用p
的promise解析函数将无法按预期工作。 这将导致p
被“锁定”在val
的状态上,这样一旦val
满足, p
将以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
有一个字段then
类型的“功能”,并有条件地包裹。
也就是说,在某些情况下,承诺解决方案的默认行为实际上可能会达到预期的效果。 因此,仅当您确定要实现而不是用第二个承诺来解决第一个承诺时,才使用上述解决方法。
尽管不同的人使用不同的术语,但在通用术语中,“实现”是指将承诺置于“成功”状态(与“拒绝”相对),该状态将触发then
处理程序将其挂起。
换句话说,您不能用承诺“履行”承诺。 您可以实现自己的价值。 (顺便说一句,“解决”一词通常指实现或拒绝。)
您可以做的是从.then
处理程序返回一个诺言,这实际上将用返回的诺言替换原始诺言。
这是一个简单的例子:
asyncTask1 . then(asyncTask2) . then(processData)
其中asyncTask1
是一个承诺,而asyncTask2
是一个返回一个承诺的函数。 所以,当asyncTask1
满足(成功完成),然后asyncTask2
运行,并通过返回的承诺.then
被“接管”的承诺asyncTask2
回报,这样,当它结束时,数据可以被处理。
我可以通过以Promise.resolve
作为参数调用Promise.resolve
来做类似的事情。 这有点用词不当,因为我没有从技术角度解决诺言。 相反,创建的新承诺被我传入的承诺“占用”。它也没有用,因为使用结果与使用我传入的承诺完全相同:
Promise.resolve(asyncTask2)
行为与
asyncTask2
(假设asyncTask2已经是一个承诺;否则Promise.resolve
可以创建一个保证,并立即通过传入的值来实现。)
就像可以将Promise.resolve
传递给Promise.resolve
,您也可以将Promise.resolve
传递给作为Promise.resolve
构造函数回调的参数提供给您的resolve
函数。 如果您传递来resolve
的参数是非承诺,则promise将立即用该值兑现。 但是,如果传递给您resolve
的参数是另一个promise,则该promise将“接管您正在构建的promise的主体”。 换句话说,您正在构造的promise的行为与传递给resolve
的promise的行为完全相同。
“精确地表现”是指,如果您传递来resolve
的诺言已经兑现,那么您正在构造的诺言将立即以相同的价值兑现。 如果您传递来resolve
的承诺已被拒绝,则您出于相同原因立即构造的承诺将被拒绝。 如果您在通过承诺resolve
尚未解决,那么任何then
处理你挂过你正在构造是否以及何时你通过的承诺将被调用的承诺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
可能是一个选择(在独立并行异步任务的情况下),方法是传递适当的对象或带有状态修饰的对象,并在适当的时候传递给已准备好的对象。 在下面的Promise.all示例中,请注意它如何在承诺中恢复-让我花了一会儿意识到如何重定向链的结果。 一切的结果只是最后诺言的回报。 尽管这不能回答问题的标题,但使用return Promise.reject(<an-object-including-a-promise>)
(或解决)可在执行过程中提供一系列和/或一组异步任务共享访问和控制。 在采摘,下载然后我拿出进度的事件处理则文件工作的情况下,这样做: pickFile.then(download,orFailGracefully)
与downloadProgress
的内部处理download
onResolve处理程序(下载进度不会出现是一个异步任务)。 以下是控制台中的相关实验。
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;
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.