【发布时间】:2015-11-17 01:03:17
【问题描述】:
我想用其他的诺言来兑现一个诺言。关键是我真的想在第一个承诺完成后立即访问(仍在等待中的)第二个 promise。不幸的是,我似乎只能在两个 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 中选择文件。它返回一个承诺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;
}
标记行中的问题是我想履行承诺p1与新承诺p2,但我只知道如何解决它。 difference between fulfilling and resolving 是解析首先检查提供的值 p2 是否再次是一个承诺。如果是,则p1 的实现将推迟到p2 实现,然后p1 将使用p2 的分辨率值而不是p2 本身来实现。
我可以通过围绕p2 构建一个包装器来解决这个问题,即替换该行
resolveP1(p2); // <--- PROBLEM: I actually want to *fulfill* p1 with p2
来自第二个代码示例
resolveP1({promise: p2});
然后,在第一个代码示例中,我必须替换该行
return downloadProgress;
通过
return downloadProgress.promise;
但是当我真正想做的只是履行(而不是解决)一个承诺时,这似乎有点像一个黑客。
如果有任何建议,我将不胜感激。
【问题讨论】:
-
Promise 会自动解包,避免这种情况的唯一方法是不使用另一个 Promise 解决,正如您所提到的。最初使用文件名或其他数据解析
result对象,然后在其上传时解析.file函数或属性是否有缺点? -
不幸的是,这在 ES6 Promise 中是不可能的。我担心这将永远无法解决,因为解决方法太简单了。
-
您的示例是演示场景还是您的团队用例?如果那是您的用户案例,那么您的事情就过于复杂了。这里唯一的异步操作是下载,所以要保证文件,然后在同步代码中完成其余的操作。一旦所有同步代码完成后,就会有一个执行函数处理该文件。
-
@Amit:也许我称它为“文件选择器”是一种误导。这不是与
<input type="file">关联的模态“打开文件”对话框。相反,pickFile显示带有一些输入字段的<form>以选择文件(本地或通过 URL)和“继续”按钮。因此,使pickFile同步将冻结浏览器并且用户将无法与表单元素进行交互。或者,从pickFile返回一个仅在下载完成后才解决的承诺意味着用户必须等待下载,即使该文件不是立即需要的。 -
@loganfsmyth:我想,在这种特定情况下,将返回的承诺包装在一个对象中是可行的,因为我已经知道我想要传递的值是一个承诺。我只是认为我错过了一些明显的替代方案,因为我认为用 any 类型的值(无论是否是承诺)履行承诺是一件相当通用的事情,所以我没有预计这是不可能的。 (假设您正在编写一个想要从异步操作“返回”一些用户定义的值的库,其中该库无法对值的类型做出任何假设)。还是谢谢!
标签: javascript ecmascript-6 es6-promise