89

使用 ES6 Promise,如何在不定义解决逻辑的情况下创建 Promise?这是一个基本示例(一些 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 :(
}

使用其他 Promise 库很容易做到这一点。以 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);
}

我能看到的唯一方法是将 resolve 函数存储在 Promise 的执行程序中的某个地方,但这看起来很混乱,而且我不确定它是在何时运行该函数时定义的——它总是在构造时立即运行吗?

谢谢。

4

6 回答 6

106

好问题!

传递给 Promise 构造函数的解析器有意同步运行以支持此用例:

var deferreds = [];
var p = new Promise(function(resolve, reject){
    deferreds.push({resolve: resolve, reject: reject});
});

然后,在稍后的某个时间点:

 deferreds[0].resolve("Hello"); // resolve the promise with "Hello"

给出 promise 构造函数的原因是:

  • 通常(但不总是)解析逻辑与创建绑定。
  • Promise 构造函数是 throw safe 并将异常转换为拒绝。

有时它不适合,因此解析器同步运行。这是有关该主题的相关阅读

于 2015-06-26T09:23:12.080 回答
59

我想在这里加我的 2 美分。正是考虑到“创建一个 es6 Promise 而不开始解决它”这个问题,我解决了它创建一个包装函数并改为调用包装函数。代码:

假设我们有一个f返回 Promise的函数

/** @return Promise<any> */
function f(args) {
   return new Promise(....)
}

// calling f()
f('hello', 42).then((response) => { ... })

现在,我想在不实际解决它的情况下准备调用:f('hello', 42)

const task = () => f('hello', 42) // not calling it actually

// later
task().then((response) => { ... })

希望这会对某人有所帮助:)


参考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 => { ... })
于 2016-11-24T13:22:03.390 回答
3

更全面的方法怎么样?

.resolve()您可以编写一个构造函数,它返回一个用和.reject()方法装饰的新 Promise 。

您可能会选择命名构造函数Deferred——在 [the history of] javascript Promise 中具有很多优先级的术语。

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

通过返回一个装饰的 promsie 而不是一个普通的对象,除了装饰之外,所有 promise 的自然方法/属性仍然可用。

此外,通过处理fn,如果您需要/选择在 Deferred 上使用它,则显示模式仍然可用。

演示

现在,有了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();
}
于 2015-06-26T13:33:00.393 回答
2

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')

显然曾经有一个Promise.defer助手,但即使这样也坚持将延迟对象与承诺本身分开......

于 2020-03-22T21:05:01.243 回答
2

我猜是什么让这类问题看起来很复杂是 Javascript 的程序性质。为了解决这个问题,我创建了一个简单的类。它的外观如下:

class PendingPromise {

    constructor(args) {
        this.args = args;
    }

    execute() {
        return new Promise(this.args);
    }
}

这个promise只会在你调用时执行execute()。例如:

function log() {
    return new PendingPromise((res, rej) => {
        console.log("Hello, World!");
    });
}

log().execute();
于 2020-11-28T08:18:14.247 回答
0

CPomise允许您在外部解决您的 Promise,但这是一种反模式,因为它破坏了 Promise 封装模型。(现场演示

import CPromise from "c-promise2";

const promise = new CPromise(() => {});

promise.then((value) => console.log(`Done: ${value}`)); //123

setTimeout(() => promise.resolve(123));
于 2020-11-28T14:13:46.003 回答