稍后解决承诺

时间:2015-12-31 01:54:37

标签: es6-promise

我想构建一个Promise,但是将解决方案推迟到以后。下面的代码创建了一个承诺,但它会立即得到解决。如何控制承诺的评估时间?

var p = new Promise((resolve, reject) => {
        resolve(1);
    })
    .then((p1) => {
        console.log(p1 + 1);
    });

更新:为了澄清,希望将promise的声明与其执行分开的原因是根据一些参数动态添加then回调。

3 个答案:

答案 0 :(得分:1)

不完全确定您的要求 - 下面的代码演示了承诺和调用then的构造以相同的顺序发生,但可能在不同的时间执行。更改wait1wait2的值,看看输出是如何不同的,但无论时间如何,代码都能正常工作。

我认为您需要实现承诺代码,以便等待您想要等待的任何条件。在示例中,它是一个简单的setTimeout,但您可以想象做任何事情来推迟执行。

您可能需要使用Chrome才能在浏览器中查看这些结果:



var wait1 = 2000;
var wait2 = 1000;

function log(...str) {
  var li = document.createElement('li');
  str.forEach((s) => {
    li.appendChild(document.createTextNode(s));
  });
  document.getElementById("log").appendChild(li);
}

var p = new Promise((resolve, reject) => {
  setTimeout(() => {
    log("Resolving promise!");
    resolve(1);
  }, wait1);
});

log("Promise created!");

setTimeout(() => {
  log("Calling 'then'");
  p.then((p1) => {
    log("Value:", p1 + 1);
  });
}, wait2);

<ol id="log" />
&#13;
&#13;
&#13;

答案 1 :(得分:0)

您可以将resolvereject传递给您要使用的任何异步函数。只要完成它的工作,这样的函数就可以调用它。这是Node中可运行的示例。如果运行它,它将在当前目录中执行ls -lexecSomething函数只需要回调,而promiseToExec函数会将resolve, reject回调传递给execSomething,而不是立即调用其中任何一个。

const childProcess = require("child_process");

function execSomething(command, options, onSuccess, onError) {
  childProcess.exec(command, options, (err, stdout, stderr) => {
    if (err) {
      onError(err);
    }
    onSuccess(stdout, stderr);
  });
}

function promiseToExec(command, options) {
  return new Promise((resolve, reject) => {
      execSomething(command, options, resolve, reject);
  });
}

promiseToExec("ls -l").then(console.log.bind(console));

Kazlauskis建议这样做:

var resolve;
var promise = new Promise(function(fulfill) {
  resolve = fulfill;
});

不要这样做!

当您传递给new Promise的回调中发生异常时,promises的规范将使异常自动转换为promise promise。因此,如果回调中有任何内容throw Error...,您将获得自动转换。

如果您保存resolve回调并将逻辑移到回调之外,则转到new Promise,那么您就不会进行此自动转换。在回调之外抛出的异常将被传递到堆栈,而不会转换为承诺拒绝。这很糟糕,因为它要求您的函数用户使用.catch来捕获被拒绝的承诺 try...catch以获取抛出的异常。这是一个糟糕的设计实践。

以下是说明问题的代码:

// This is how things should be done.
function makeGoodPromise(num) {
  return new Promise((resolve) => {
    if (num < 0) {
      throw new Error("negative num");
    }
    resolve(num);
  });
}

// This is a bad approach because it will sometimes result in synchronous
// exceptions.
function makeBadPromise(num) {
  let resolve;
  const p = new Promise((fullfil) => {
    resolve = fullfil;
  });

  if (num < 0) {
    throw new Error("negative num");
  }
  resolve(num);

  return p;
}

// Shoring up the bad approach with a try... catch clause. This illustrates what
// you need to do convert the exception into a rejection. However, why deal with the
// additional scaffolding when you can just take the simpler approach of not
// leaking the callbacks??
function makeBadPromise2(num) {
  let resolve, reject;
  const p = new Promise((fullfil, deny) => {
    resolve = fullfil;
    reject = deny;
  });

  try {
    if (num < 0) {
      throw new Error("negative num");
    }
    resolve(num);
  }
  catch (e) {
    reject(e);
  }

  return p;
}


makeGoodPromise(-1).catch(() => console.log("caught the good one!"));

try  {
  makeBadPromise(-1).catch(() => console.log("caught the bad one!"));
}
catch(e) {
  console.log("Oops! Synchronous exception: ", e);
}

makeBadPromise2(-1).catch(() => console.log("caught the bad2 one!"));

当我在Node中执行它时,这是输出:

Oops! Synchronous exception:  Error: negative num
    at makeBadPromise (/tmp/t12/test2.js:17:11)
    at Object.<anonymous> (/tmp/t12/test2.js:48:3)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.runMain (module.js:604:10)
    at run (bootstrap_node.js:394:7)
    at startup (bootstrap_node.js:149:9)
caught the good one!
caught the bad2 one!

答案 2 :(得分:-1)

不确定这是否是最佳方式,但您可以:

var resolve;
var promise = new Promise(function(fulfill) {
  resolve = fulfill;
});

// now you can resolve the promise whenever you want 
promise.then(function() {
  console.log('done!');
});

resolve();