简体   繁体   English

使用Javascript原生Promise,在附加ableable之后解析Promise

[英]Using Javascript native promises, resolve a promise after thenables attached

Is there a way using javascript native promises ( docs ) to create a promise and attach thenables, without knowing at constructor time how it will resolve? 有没有一种方法可以使用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

If result of promise depends on other promise, you should just create a promise using then . 如果承诺的结果取决于其他承诺,则应使用then创建一个承诺。

What was proposed by @Norguard in direct form, doesn't make much sense (it's even coined as deferred anti-pattern ). @Norguard以直接形式提出的建议没有多大意义(甚至被称为递延反模式 )。 Below code does exactly same, and no extra promise is needed: 下面的代码做的完全一样,不需要额外的承诺:

var deferredSomething = function () {
  return waitAWhile()
      .then(doStuff)
      .then(function (result) {
          if (result.isGood) {
            return result.data;
          } else {
            throw result.error;
          }
       });
  });
};

And, even if, for whatever reason you would need to create promise upfront, then with constructor pattern it would be cleaner to do it that way: 而且,即使出于任何原因,您都需要预先创建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);
          }
       });
  });
};

Simply save them inside of a closure. 只需将它们保存在闭包中即可。

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

This is actually the majority of the difference between the "deferred" concept and the "promise" concept; 实际上,这是“递延”概念和“承诺”概念之间的大部分差异。 one more level, on top, that has the actual remote-controls that you can give to someone else, while you hand the .then|.success|.done|etc... to your consumers. 最顶层,它具有您可以将.then|.success|.done|etc...交给消费者时可以提供给其他人的实际遥控器。

Once you bring those functions out into your upstream process, you can happily lazy-load whatever you'd like, using the "thenable" which you'll return, and then succeed or fail your chain (or leave it hanging) at will... 将这些功能带入上游流程后,您可以使用返回的“ thenable”愉快地延迟加载任何所需的东西,然后随意使链成功或失败(或使其挂起)。 ..

UPDATE 更新

Seeing as this is probably going to continue to be the chosen answer, and continue to be voted down, as the solution to the exact problem he was having (ie: retrofitting code which was not made with ES6 promises in mind), I figure I'll add a more detailed example of exactly why using this antipattern selectively can be better than naught: 我认为,这很可能将继续是选择的答案,并继续被否决,这是他所遇到的确切问题的解决方案(即:改版代码不是考虑到ES6的承诺),我认为我们将添加一个更详细的示例,说明为什么有选择地使用此反模式可能比没有效果更好的原因:

MongoClient.connect("mongodb://localhost:21017/mydb", (err, db) => {
    db.collection("mycollection", (err, collection) => {
        collection.find().toArray((err, results) => {
            doStuff(results);
        });
    });
});

If I were to write a library, here, hoping to reach the point where I could write: 如果要编写一个库,请在这里,希望可以写点:

let dbConnected = MongoClient.connect(dbURL);

dbConnected
    .then(db => db.collection(myCollection))
    .then(collection => collection.find(query))
    .then(stream => doStuff(stream));

...or alternatively: ...或者:

composeAsync(
    (stream) => doStuff(stream),
    (collection) => collection.find(query),
    (db) => dbCollection(myCollection)
)(dbConnected);

...for ease of use within the library, does it make sense to wrap every single function-body within an instantiated promise // find = curry(query, collection) return new Promise(resolve, reject) { /* whole function body, here / / do lots of stuff which is irrelevant to the resolution of mongo.db.collection.find, but is relevant to its calling */ collection.find(query).toArray( / node-callback /(err, result) { if (err) { reject(err); } else { resolve(result); } }); ...为了便于在库中使用,将每个函数体包装在实例化的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);}}); }; };

...or in looking at the pattern of really only requiring the node-specific callback to be resolved, does it make more sense to have some form of promise-resolver, to save having to write out / copy-paste a half-dozen purely-redundant lines which should be completely DRYed up? ...或者看一下只需要解决特定于节点的回调的模式,是否有某种形式的promise-resolver更有意义,从而省去了写/复制粘贴的次数应该完全干燥的纯冗余线路?

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

Yes, that is an anti-pattern... ...yet, an antipattern which requires fewer keystrokes, restores the natural flow of the promise-chain, fixes a problem with Node's callback-only API, reduces the potential for errors, et cetera. 是的,这是一种反模式... ...但是,这种反模式需要较少的击键,恢复了promise链的自然流,修复了Node的仅用于回调的API的问题,降低了发生错误的可能性等等等

Yes, there are already libraries which do this... ...solutions specific to X library or Y... ...or solutions which globally override methods of various modules (scary) ...or solutions which, again, basically force you to pass in all of the details of the call you're making: 是的,已经有执行此操作的库...针对X库或Y特定的解决方案...或全局覆盖各种模块(可怕)方法的解决方案...或基本上迫使您传递正在拨打的电话的所有详细信息:

wrapNodeMethod(fs, "read", url, config).then(data => { /*...*/ });

But there is no simple solution for the case of inverting all of that pain, without either: 但是,要消除所有这些痛苦,却没有一个简单的解决方案:

a) wrapping the entire function body in a promise, to feed the async callback a resolver b) using an antipattern within a library, in order to pass Node callbacks a resolver that the rest of the function-body needs to know precisely nothing about. a)将整个函数体包装在promise中,以将异步回调提供给解析器b)在库中使用反模式,以便将其他函数体完全不需要了解的解析器传递给Node回调。

Even if data needed to be transformed within the resolver, it would still make more sense to return a transformed set, in a new promise 即使数据需要在解析器中进行转换,以新的承诺返回转换后的集合仍然更有意义。

let resolver = new NodeResolver();
somethingAsync(resolver.resolve);
return resolver.promise.then(transformData).then(logTransform);

...than to wrap the whole body, including transforms, etc, just for closure-scope reference, just for the sake of avoiding an "antipattern" which clearly goes against the grain of what has become a very prominent JS platform/paradigm. ...而不是包装整个身体(包括变换等),仅用于闭包范围参考,只是为了避免使用“反模式”,而这种“反模式”明显违背了非常著名的JS平台/范例。

Now, personally, I'd be happier if IO||Node methods returned a promise and/or a stream, as well as taking a callback, as a core part of the platform... ...that's not going to happen... 现在,就个人而言,如果IO || Node方法返回promise和/或流,以及进行回调,并将其作为平台的核心部分,我会更开心……这将不会发生。 ..

...but you can't possibly tell me that writing less, and keeping Node modules DRY, while still using ES6 Promises is an "antipattern", without providing me a more-eloquent solution, therefore. ...但是您可能无法告诉我,在仍然使用ES6 Promises的情况下,减少编写并保持Node模块为DRY是一种“反模式”,因此没有为我提供更为雄辩的解决方案。

If you can, indeed, provide me something that I can use in any NodeJS callback, which does, indeed, provide a more eloquent solution to this, such that I don't have to wrap every body of every method which contains an async callback in a new constructor, or use clunky dispatcher methods, or hijack entire modules to override their global functionality... 如果确实可以为我提供可以在任何 NodeJS回调中使用的功能,那么它的确提供了一种更为雄辩的解决方案,从而使我不必包装每个包含异步回调的方法的每个主体。在新的构造函数中,或者使用笨拙的调度程序方法,或者劫持整个模块以覆盖其全局功能...

...I'd be more than willing to retract my statement that this particular pattern is still highly-useful, as regards interfacing with APIs which are prone to pyramids o'dewm. ...我很乐意收回我的声明,即与容易产生金字塔的API接口时,这种特定模式仍然非常有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM