使用Javascript本机promise,在附加了promise之后解析一个promise



有没有一种方法可以使用javascript原生promise(docs)创建promise并附加二进制文件,而不需要在构造函数时知道它将如何解决?

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

只需将它们保存在闭包中即可。

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...交给消费者时,您可以将实际的遥控器交给其他人。

一旦你把这些功能引入到你的上游流程中,你就可以很高兴地懒惰地加载你想要的任何东西,使用你将返回的"theable",然后随意地成功或失败你的链(或让它挂着)。。。

更新

鉴于这可能会继续成为他所选择的答案,并继续被否决,作为他所面临的确切问题的解决方案(即:对没有考虑到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);

为了便于在库中使用,将每个函数体封装在实例化的promise中有意义吗//find=curry(查询,集合)返回新的Promise(解决、拒绝){/*整个功能体,此处//做了很多与mongo.db.collection.find的解析无关的事情,但与它的调用有关*/collection.find(query).toArray(/节点回调/(err,result){if(err){拒绝(err);}其他{解决(结果);}});};

或者,在考虑真正只需要解决特定于节点的回调的模式时,使用某种形式的promise解析器是否更有意义,以避免必须写出/复制粘贴六条应该完全DRYed的纯冗余行?

// find = curry(query, collection)
let resolver = new NodeResolver();
collection.find(query).toArray(promise.resolve);
return resolver.promise;

是的,这是一种反模式。。。然而,反模式需要更少的击键,恢复promise-chain的自然流,修复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模块干燥是一种"反模式"。

如果你真的能为我提供一些我可以在任何NodeJS回调中使用的东西,这确实提供了一个更有力的解决方案,这样我就不必在新的构造函数中包装包含异步回调的每个方法的每一个主体,也不必使用笨拙的调度器方法,或者劫持整个模块来覆盖它们的全局功能。。。

我非常愿意收回我的说法,即这种特定的模式仍然非常有用,与容易出现金字塔形的API接口。

如果promise的结果依赖于其他promise,则应该使用then创建一个promise。

@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);
}
});
});
};

最新更新