在它存在之前等待承诺

时间:2017-06-15 10:50:09

标签: javascript node.js promise

我正在收听用户事件,其中一些取决于其他人的完成情况。处理这些事件是异步任务,因此我使用承诺

让我说我得到了这个:

A
  -> B
       -> C
       -> ...
       -> D
            -> E
            -> ...
            -> F

我最初的做法是保存A的承诺,并使用B then 方法附加A的处理诺言。 BC ... DD以及E ... F也是如此。

但这些事件几乎可以在同一时间发生, B可能会在A 之前发生。由于我无法听取尚未存在的承诺 ......您如何解决这个问题?

我的想法是为每个级别(A,B,D)定义一个对象,我可以附加一个承诺处理未来事件即可。附加承诺时,我会迭代处理未来事件并将其设置为承诺then。附加未来事件时,我会查看是否有承诺,并将其附加到then或将其保存到数组或其他内容中。

您是否知道现有的解决方案已经解决了这个问题,或者我是否应该遵循我的想法?

谢谢。

按要求进一步澄清:

我正在收听客户端的多媒体事件,这些事件通过websocket(使用socket.io)转发到服务器。事件的顺序确实是第一个A,然后是B,等等。但由于它们中的一些几乎同时发生,所以它们可以不按顺序处理。

示例代码

let promiseForA, promiseForB;

socket.on('A', data => {
  promiseForA = asynchronousTaskForA();
});

socket.on('B', data => {
  // What if promiseForA has not yet been defined?
  promiseForA.then(neededValue => {
    asynchronousTaskForB(neededValue);
  });
});

socket.on('C', data => {
  // What if promiseForB has not yet been defined?
  promiseForB.then(neededValue => {
    asynchronousTaskForC(neededValue);
  });
});

socket.on('D', data => {
  // What if promiseForB has not yet been defined?
  promiseForB.then(neededValue => {
    asynchronousTaskForD(neededValue);
  });
});

function asynchronousTaskForA() {
  // something
  resolve('something needed by B');
}

function asynchronousTaskForB(value) {
  // something with value
  resolve('something needed by C ... D');
}

function asynchronousTaskForC(value) {
  // something with value
  resolve();
}

function asynchronousTaskForD(value) {
  // something with value
  resolve('something needed by E ... F');
}

我的想法

所以......它有效。它可能是反模式,错误或疯狂,但......我想知道一个更好的选择。

let PromiseWaiter = function() {
    let promise = null;
    let thens = [];

    let self = this;

    this.setPromise = function (p) {
        promise = p;
        thens.forEach(t => {
            p.then(t);
        });
    };

    this.then = function(t) {
        if (promise === null) {
            thens.push(t);
        } else {
            promise.then(t);
        }
        return self;
    };

    this.reset = function() {
        promise = null;
        thens = [];
    };
};

module.exports = PromiseWaiter;

使用它:

let waitForA = new PromiseWaiter();
let waitForB = new PromiseWaiter();
let waitForD = new PromiseWaiter();

socket.on('A', data => {
  waitForA.setPromise(asynchronousTaskForA());
});

socket.on('B', data => {
  waitForA.then(neededValue => {
    waitForB.setPromise(asynchronousTaskForB(neededValue));
  });
});

socket.on('C', data => {
  waitForB.then(neededValue => {
    asynchronousTaskForC(neededValue);
  });
});

socket.on('D', data => {
  waitForB.then(neededValue => {
    waitForD.setPromise(asynchronousTaskForD(neededValue));
  });
});

// Note: I am confused why these functions did not return a Promise before
// They have always done that.
function asynchronousTaskForA() {
  return new Promise((resolve, reject) => {
    // something
    resolve('something needed by B');
  });
}

function asynchronousTaskForB(value) {
  return new Promise((resolve, reject) => {
    // something with value
    resolve('something needed by C ... D');
  });
}

function asynchronousTaskForC(value) {
  return new Promise((resolve, reject) => {
    // something with value
    resolve();
  });
}

function asynchronousTaskForD(value) {
  return new Promise((resolve, reject) => {
    // something with value
    resolve('something needed by E ... F');
  });
}

谢谢!

2 个答案:

答案 0 :(得分:2)

  

如果尚未定义promiseForA该怎么办?

不要异步分配给它。立即创建它 - 为它做出承诺。哦,对承诺的承诺只是一种承诺。

const A = new Promise(resolve => socket.on('A', resolve));
const B = new Promise(resolve => socket.on('B', resolve));
const C = new Promise(resolve => socket.on('C', resolve));
const D = new Promise(resolve => socket.on('D', resolve));

const afterA = A.then(asynchronousTaskForA);
const afterB = Promise.all([afterA, B]).then(asynchronousTaskForB);
const afterC = Promise.all([afterB, C]).then(asynchronousTaskForC);
const afterD = Promise.all([afterB, D]).then(asynchronousTaskForD);
  

我的想法可能是反模式,错误或疯狂,但......它有效。

呀。我看到的问题是,它看起来非常像一个承诺(或延期),但不是一个:

  • setPromise只是resolve
  • then确实注册了回调,但没有返回等待回调结果的承诺,因此无法链接
  • 承诺 1 是不可能的
  • reset,但我不确定你是否真的需要这个。

正如我在评论中所说,最好不要推出自己的解决方案,只需使用Promise即可。当然,您可以编写辅助函数socket.getPromiseForNext('A')左右。

1:但您可以使用支持取消的Creed之类的实现。我怀疑只是创建一个等待下一个事件的新实例应该足够了。

答案 1 :(得分:0)

您可以在then回调的return语句中创建一个promise。 例如:

promiseA
  .then( data => {
     return new Promise((resolve, reject) => {
       // do some job
     });
  })

就使用节点而言,您可以使用async / await方法:

async function startFlow() {
  // here you sure create promise, instead of promise A
  const res1 = await promiseA;

  // here you sure create promise, instead of promise B
  const res2 = await promiseB;

  // etc...
}

// Start your functions execution
startFlow();