[英]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.