推迟执行Promise构造函数,但仍然能够链接处理程序

时间:2018-03-13 18:10:43

标签: javascript promise es6-promise

有时我想推迟promise构造函数的执行,但仍然可以定义promise链。我发现并略微调整了以下方法,但由于我对承诺的经验很少,我想知道

  • 是否有更简洁的方法来做到这一点?
  • 我用这种方法失去了什么?



class Deferred {
  constructor() {
    this.promise = new Promise((r, e) => {
      // arrows use this of their surrounding scope
      this.resolve = r;
      this.reject = e;
    });

    this.then = this.promise.then.bind(this.promise);
    this.catch = this.promise.catch.bind(this.promise);
    this.finally = this.promise.finally.bind(this.promise);
  }
}

const sqrAsync = n => {
  const d = new Deferred;
  
  d.runPromise = () => typeof n === "number"
    ? setTimeout(d.resolve, 0, n * n)
    : setTimeout(d.reject, 0, new Error("number expected"));
   
  return d;
};

const deferred = sqrAsync(5),
  deferred2 = sqrAsync("foo");

deferred
  .then(console.log)
  .catch(console.error)
  .finally(() => console.log("clean up 1st"));

deferred2
  .then(console.log)
  .catch(console.error)
  .finally(() => console.log("clean up 2nd"));

deferred.runPromise();
deferred2.runPromise();




我知道我可以使用userland的Task / Furture实现来实现这个和其他所需的属性,我通常会这样做。但是,有时我需要ES6 Promise互操作。

预测原因:我想分开"有效的"从我的程序的其余部分计算。

3 个答案:

答案 0 :(得分:1)

老实说,不要这样做。推迟被推荐是有充分理由的。

function sqrAsync(n) {
  return new Promise((resolve, reject) => {
    if (typeof n === "number")
      setTimeout(resolve, 0, n * n);
    else
      setTimeout(reject, 0, new Error("number expected"));
  });
}

var start1, start2;

const p1 = new Promise(resolve => { start1 = resolve; }).then(() => sqrAsync(5));
const p2 = new Promise(resolve => { start2 = resolve; }).then(() => sqrAsync("foo"));

p1.then(console.log, console.error).finally(() => console.log("clean up 1st"));
p1.then(console.log, console.error).finally(() => console.log("clean up 2nd"));

start1();
start2();

您永远不需要推迟promise构造函数的执行。如果你需要在开始你的行动之前等待一些东西,那就是回复一个承诺 - 为这个东西做出承诺。

答案 1 :(得分:1)

re:更简洁的方法

您的sqrAsync功能可以像这样重写:

function sqrAsync(n) {
  if (typeof n === 'number')
    return Promise.resolved(n * n);
  return Promise.reject(new Error('number expected'));
}

或者,使用async

async function sqrAsync(n) {
  if (typeof n === 'number')
    return n * n;
  throw new Error('number expected');
}

你的Deferred确实更灵活,但我同意Jonas的意见,因为用例很少见。

re:我失去了什么

你失去的一件事是,通过这样做,你假设Promise原型总是有thencatchfinally而没有别的。如果你真的想这样做,你应该考虑扩展Promise。例如在node.js中,不支持finally(支持自cli标志后面的v8.1.4+)并且您的代码将抛出“无法读取未定义的属性'绑定”错误。

正如@Bergi在评论中指出的那样,对于我们假设Promise原型的问题,不绑定任何方法都会解决问题。这可能会使课程更难使用。另一种可能是Promise的looping through ownProperties来找出方法列表。我不想成为维护这段代码的人。

答案 2 :(得分:0)

来自MDN documentation

  

执行函数由Promise实现立即执行,传递resolve和reject函数(在Promise构造函数甚至返回创建的对象之前调用执行程序。)

Promise旨在抽象异步执行的行为,以及可能的失败。你要找的是延迟执行,或者可能是懒惰的执行。我不认为Promise会为你提供一个简单的方法来实现这一目标。