创建(ES6)承诺而不开始解决它

时间:2015-06-26 09:20:54

标签: javascript promise es6-promise

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

使用其他承诺库轻松完成。以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);
}

我能看到这样做的唯一方法是将解析功能存储在承诺执行者的某个地方,但这看起来很混乱,而且我不确定它是在确切的时候定义的这个功能运行 - 是否总是在施工时立即运行?

感谢。

6 个答案:

答案 0 :(得分:57)

好问题!

传递给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构造函数是throw安全的,并将异常转换为拒绝。

有时它不适合,并且旋转变压器同步运行。 Here is related reading on the topic

答案 1 :(得分:35)

我想在这里加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 => { ... })

答案 2 :(得分:3)

更全面的方法怎么样?

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

你可能会选择命名构造函数Deferred - 这个术语在[javascript promises的历史]中有很多优先权。

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,如果您需要/选择在延期中使用它,那么揭示模式仍然可用。

<强> DEMO

现在,使用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();
}

答案 3 :(得分:1)

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助手,但即使如此,仍坚持将延迟对象与诺言本身分开……

答案 4 :(得分:1)

我认为,使这类问题看起来复杂的原因是Javascript的过程性质。为了解决这个问题,我创建了一个简单的类。外观如下:

class PendingPromise {

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

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

仅当您致电execute()时,才会执行此承诺。例如:

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

log().execute();

答案 5 :(得分:0)

CPomise允许您在外部解决承诺,但这是一种反模式,因为它破坏了Promise封装模型。 (Live demo

import CPromise from "c-promise2";

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

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

setTimeout(() => promise.resolve(123));