Javascript 创建(ES6)承诺而不开始解决它
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31069453/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Creating a (ES6) promise without starting to resolve it
提问by Barguast
Using ES6 promises, how do I create a promise without defining the logic for resolving it? Here's a basic example (some TypeScript):
使用 ES6 承诺,如何在不定义解决逻辑的情况下创建承诺?这是一个基本示例(一些 TypeScript):
var promises = {};
function waitFor(key: string): Promise<any> {
if (key in promises) {
return promises[key];
}
var promise = new Promise(resolve => {
// But I don't want to try resolving anything here :(
});
promises[key] = promise;
return promise;
}
function resolveWith(key: string, value: any): void {
promises[key].resolve(value); // Not valid :(
}
It's easily done with other promise libraries. JQuery's for example:
使用其他承诺库可以轻松完成。以 JQuery 为例:
var deferreds = {};
function waitFor(key: string): Promise<any> {
if (key in promises) {
return deferreds[key].promise();
}
var def = $.Deferred();
deferreds[key] = def;
return def.promise();
}
function resolveWith(key: string, value: any): void {
deferreds[key].resolve(value);
}
The only way I can see to do this would be to store the resolve function away somewhere within the promise's executor but that seems messy, and I'm not sure it's defined when exactly this function is run - is it always run immediately on construction?
我能看到的唯一方法是将 resolve 函数存储在 promise 的执行器中的某个地方,但这看起来很混乱,而且我不确定它是在运行该函数时定义的 - 它是否总是在构建时立即运行?
Thanks.
谢谢。
回答by Benjamin Gruenbaum
Good question!
好问题!
The resolver passed to the promise constructor intentionally runs synchronous in order to support this use case:
传递给 promise 构造函数的解析器有意同步运行以支持此用例:
var deferreds = [];
var p = new Promise(function(resolve, reject){
deferreds.push({resolve: resolve, reject: reject});
});
Then, at some later point in time:
然后,在稍后的某个时间点:
deferreds[0].resolve("Hello"); // resolve the promise with "Hello"
The reason the promise constructor is given is that:
给出承诺构造函数的原因是:
- Typically (but not always) resolution logic is bound to the creation.
- The promise constructor is throw safe and converts exceptions to rejections.
- 通常(但并非总是)解析逻辑与创建绑定。
- 承诺构造函数是抛出安全的,并将异常转换为拒绝。
Sometimes it doesn't fit and for that it the resolver runs synchronously. Here is related reading on the topic.
有时它不适合,因此解析器同步运行。这是有关该主题的相关阅读。
回答by Manu
I want to add my 2 cents here. Considering exactly the question "Creating a es6 Promise without starting resolve it" I solved it creating a wrapper function and calling the wrapper function instead. Code:
我想在这里加上我的 2 美分。考虑到问题“在没有开始解析的情况下创建一个 es6 Promise”,我解决了它创建一个包装函数并调用包装函数的问题。代码:
Let's say we have a function f
which returns a Promise
假设我们有一个f
返回 Promise的函数
/** @return Promise<any> */
function f(args) {
return new Promise(....)
}
// calling f()
f('hello', 42).then((response) => { ... })
Now, I want to preparea call to f('hello', 42)
without actually solving it:
现在,我想准备一个电话f('hello', 42)
而不实际解决它:
const task = () => f('hello', 42) // not calling it actually
// later
task().then((response) => { ... })
Hope this will help someone :)
希望这会帮助某人:)
Referencing Promise.all()
as asked in the comments (and answered by @Joe Frambach), if I want to preparea call to f1('super')
& f2('rainbow')
, 2 functions that return promises
参考Promise.all()
评论中的要求(并由@Joe Frambach 回答),如果我想准备对f1('super')
&的调用f2('rainbow')
,2 个返回承诺的函数
const f1 = args => new Promise( ... )
const f2 = args => new Promise( ... )
const tasks = [
() => f1('super'),
() => f2('rainbow')
]
// later
Promise.all(tasks.map(t => t()))
.then(resolvedValues => { ... })
回答by Roamer-1888
How about a more comprehensive approach?
更全面的方法怎么样?
You could write a Constructor that returns a new Promise decorated with .resolve()
and .reject()
methods.
您可以编写一个构造函数,它返回一个用.resolve()
和.reject()
方法装饰的新 Promise 。
You would probably choose to name the constructor Deferred
- a term with a lot of precedence in [the history of] javascript promises.
您可能会选择命名构造函数Deferred
——一个在 javascript 承诺的 [历史] 中有很多优先级的术语。
function Deferred(fn) {
fn = fn || function(){};
var resolve_, reject_;
var promise = new Promise(function(resolve, reject) {
resolve_ = resolve;
reject_ = reject;
fn(resolve, reject);
});
promise.resolve = function(val) {
(val === undefined) ? resolve_() : resolve_(val);
return promise;//for chainability
}
promise.reject = function(reason) {
(reason === undefined) ? reject_() : reject_(reason);
return promise;//for chainability
}
promise.promise = function() {
return promise.then(); //to derive an undecorated promise (expensive but simple).
}
return promise;
}
By returning a decorated promsie rather than a plain object, all the promise's natural methods/properties remain available in addition to the decorations.
通过返回装饰的promsie 而不是普通对象,除了装饰之外,所有promise 的自然方法/属性仍然可用。
Also, by handling fn
, the revealer pattern remains availble, should you need/choose to use it on a Deferred.
此外,通过处理fn
,揭示者模式仍然可用,如果您需要/选择在延迟上使用它。
Now, with the Deferred()
utility in place, your code is virtually identical to the jQuery example.
现在,有了该Deferred()
实用程序,您的代码实际上与 jQuery 示例完全相同。
var deferreds = {};
function waitFor(key: string): Promise<any> {
if (key in promises) {
return deferreds[key].promise();
}
var def = Deferred();
deferreds[key] = def;
return def.promise();
}
回答by seanlinsley
Things are slowly getting better in JavaScript land, but this is one case where things are still unnecessarily complicated. Here's a simple helper to expose the resolve and reject functions:
JavaScript 领域的情况正在慢慢好转,但这是事情仍然不必要地复杂的一种情况。这是一个公开解析和拒绝函数的简单助手:
Promise.unwrapped = () => {
let resolve, reject, promise = new Promise((_resolve, _reject) => {
resolve = _resolve, reject = _reject
})
promise.resolve = resolve, promise.reject = reject
return promise
}
// a contrived example
let p = Promise.unwrapped()
p.then(v => alert(v))
p.resolve('test')
Apparently there used to be a Promise.defer
helper, but even that insisted on the deferred object being separate from the promise itself...
显然曾经有一个Promise.defer
助手,但即使这样也坚持将延迟对象与承诺本身分开......