[英]Using Javascript native promises, resolve a promise after thenables attached
有没有一种方法可以使用javascript本机promise( docs )创建promise并附加thenable,而在构造函数时不知道它将如何解决?
var foo = new Promise(function(resolve, reject) {
// I don't know how this will resolve yet as some other object will resolve it
});
foo.then(function(val) {
console.log("first " + val);
});
foo.resolve("bar");
foo.then(function(val) {
console.log("second " + val);
});
// result
// first bar
// second bar
如果承诺的结果取决于其他承诺,则应使用then
创建一个承诺。
@Norguard以直接形式提出的建议没有多大意义(甚至被称为递延反模式 )。 下面的代码做的完全一样,不需要额外的承诺:
var deferredSomething = function () {
return waitAWhile()
.then(doStuff)
.then(function (result) {
if (result.isGood) {
return result.data;
} else {
throw result.error;
}
});
});
};
而且,即使出于任何原因,您都需要预先创建promise,然后使用构造函数模式,这样做会更清洁:
var deferredSomething = function () {
return new Promise(function (resolve, reject) {
waitAWhile()
.then(doStuff)
.then(function (result) {
if (result.isGood) {
resolve(result.data);
} else {
reject(result.error);
}
});
});
};
只需将它们保存在闭包中即可。
var makePromise = function () {
var resolvePromise = null,
rejectPromise = null,
promise = new Promise(function (resolve, reject) {
resolvePromise = resolve;
rejectPromise = reject;
});
return { promise : promise, resolve : resolvePromise, reject : rejectPromise };
};
var deferredSomething = function () {
var deferredThing = makePromise();
waitAWhile()
.then(doStuff)
.then(function (result) {
if (result.isGood) {
deferredThing.resolve(result.data);
} else {
deferredThing.reject(result.error);
}
});
return deferredThing.promise;
};
实际上,这是“递延”概念和“承诺”概念之间的大部分差异。 最顶层,它具有您可以将.then|.success|.done|etc...
交给消费者时可以提供给其他人的实际遥控器。
将这些功能带入上游流程后,您可以使用返回的“ thenable”愉快地延迟加载任何所需的东西,然后随意使链成功或失败(或使其挂起)。 ..
我认为,这很可能将继续是选择的答案,并继续被否决,这是他所遇到的确切问题的解决方案(即:改版代码不是考虑到ES6的承诺),我认为我们将添加一个更详细的示例,说明为什么有选择地使用此反模式可能比没有效果更好的原因:
MongoClient.connect("mongodb://localhost:21017/mydb", (err, db) => {
db.collection("mycollection", (err, collection) => {
collection.find().toArray((err, results) => {
doStuff(results);
});
});
});
如果要编写一个库,请在这里,希望可以写点:
let dbConnected = MongoClient.connect(dbURL);
dbConnected
.then(db => db.collection(myCollection))
.then(collection => collection.find(query))
.then(stream => doStuff(stream));
...或者:
composeAsync(
(stream) => doStuff(stream),
(collection) => collection.find(query),
(db) => dbCollection(myCollection)
)(dbConnected);
...为了便于在库中使用,将每个函数体包装在实例化的Prom中是否有意义// find = curry(query,collection)return new Promise(resolve,reject){/ *整个函数体,在这里//做很多与mongo.db.collection.find的分辨率无关的事情,但与它的调用* / collection.find(query).toArray(/ node-callback /(err,result)有关) {if(err){reject(err);} else {resolve(result);}}); };
...或者看一下只需要解决特定于节点的回调的模式,是否有某种形式的promise-resolver更有意义,从而省去了写/复制粘贴的次数应该完全干燥的纯冗余线路?
// find = curry(query, collection)
let resolver = new NodeResolver();
collection.find(query).toArray(promise.resolve);
return resolver.promise;
是的,这是一种反模式... ...但是,这种反模式需要较少的击键,恢复了promise链的自然流,修复了Node的仅用于回调的API的问题,降低了发生错误的可能性等等等
是的,已经有执行此操作的库...针对X库或Y特定的解决方案...或全局覆盖各种模块(可怕)方法的解决方案...或基本上迫使您传递正在拨打的电话的所有详细信息:
wrapNodeMethod(fs, "read", url, config).then(data => { /*...*/ });
但是,要消除所有这些痛苦,却没有一个简单的解决方案:
a)将整个函数体包装在promise中,以将异步回调提供给解析器b)在库中使用反模式,以便将其他函数体完全不需要了解的解析器传递给Node回调。
即使数据需要在解析器中进行转换,以新的承诺返回转换后的集合仍然更有意义。
let resolver = new NodeResolver();
somethingAsync(resolver.resolve);
return resolver.promise.then(transformData).then(logTransform);
...而不是包装整个身体(包括变换等),仅用于闭包范围参考,只是为了避免使用“反模式”,而这种“反模式”明显违背了非常著名的JS平台/范例。
现在,就个人而言,如果IO || Node方法返回promise和/或流,以及进行回调,并将其作为平台的核心部分,我会更开心……这将不会发生。 ..
...但是您可能无法告诉我,在仍然使用ES6 Promises的情况下,减少编写并保持Node模块为DRY是一种“反模式”,因此没有为我提供更为雄辩的解决方案。
如果确实可以为我提供可以在任何 NodeJS回调中使用的功能,那么它的确提供了一种更为雄辩的解决方案,从而使我不必包装每个包含异步回调的方法的每个主体。在新的构造函数中,或者使用笨拙的调度程序方法,或者劫持整个模块以覆盖其全局功能...
...我很乐意收回我的声明,即与容易产生金字塔的API接口时,这种特定模式仍然非常有用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.