JavaScript工作队列

JavaScript工作队列,javascript,promise,bluebird,Javascript,Promise,Bluebird,我创建了这个对象,它包含一个数组,用作工作队列 它的工作原理是这样的: var work1 = new Work(); var work2 = new Work(); var queue = Workqueue.instance(); queue.add(work1) // Bluebird promise. .then(function addWork2() { return queue.add(work2); }) .then(function toCommit() { retur

我创建了这个对象,它包含一个数组,用作工作队列

它的工作原理是这样的:

var work1 = new Work();
var work2 = new Work();
var queue = Workqueue.instance();

queue.add(work1) // Bluebird promise.
.then(function addWork2() {
  return queue.add(work2);
})
.then(function toCommit() {
  return queue.commit();
})
.then(function done(results) {
  // obtain results here.
})
.catch(function(err){});
var work1 = new Work();
var work2 = new Work();
var queue = Workqueue.instance();

queue.add(work1)
.then(function toCommit1() {
  return queue.commit();
})
.then(function done1(result1) {
  // obtain result1 here.
})
.catch(function(err){});

queue.add(work2)
.then(function toCommit2() {
  return queue.commit();
})
.then(function done2(result2) {
  // obtain result2 here.
})
.catch(function(err){});
它在这种情况下工作,我可以在调用commit之前提交多个任务

但是如果是这样的话:

var work1 = new Work();
var work2 = new Work();
var queue = Workqueue.instance();

queue.add(work1) // Bluebird promise.
.then(function addWork2() {
  return queue.add(work2);
})
.then(function toCommit() {
  return queue.commit();
})
.then(function done(results) {
  // obtain results here.
})
.catch(function(err){});
var work1 = new Work();
var work2 = new Work();
var queue = Workqueue.instance();

queue.add(work1)
.then(function toCommit1() {
  return queue.commit();
})
.then(function done1(result1) {
  // obtain result1 here.
})
.catch(function(err){});

queue.add(work2)
.then(function toCommit2() {
  return queue.commit();
})
.then(function done2(result2) {
  // obtain result2 here.
})
.catch(function(err){});
可能会出现问题,因为如果在第二次提交之后调用第一次提交(已经添加了两个工作/任务),第一次提交处理程序期望得到一个结果,但它们都会转到第二次提交处理程序

该任务涉及Web SQL数据库读取,也可能涉及网络访问。因此,这基本上是一个复杂的过程,所以上述问题可能会浮出水面。如果我能实现一个
addWorkAndCommit()
,它将
add
commit
包装在一起,但是仍然没有保证,因为
addWorkAndCommit()
在某种意义上不能是“原子的”,因为它们涉及异步调用。因此,即使对
addWorkAndCommit()
的两次调用也可能失败。(我不知道如何用“原子”来描述它,因为JavaScript是单线程的,但是这个问题突然出现了)


我能做什么?

问题是有一个
commit()
,但没有事务的概念,因此不能显式地让两个独立的事务并行运行。据我所知,Javascript
Workqueue
是远程队列的代理,对
add()
commit()
的调用直接映射到某种远程过程调用,这些调用具有类似的接口,没有事务。我也明白,如果第二个
add()
实际上发生在第一个
commit()
之后,您不会在意,您只需要编写两个简单的后续
addWorkAndCommit()
语句,而不必同步客户端代码中的底层调用


您可以做的是在本地
工作队列
周围编写一个包装器(如果它是您的代码,也可以直接修改它),这样队列的每次更新都会创建一个新事务,并且
提交()
始终引用一个这样的事务。然后,包装器延迟新的更新,直到提交(或回滚)所有以前的事务。

采纳Benjamin Grunbaum的建议,使用disposer模式,下面是一个,作为
Workqueue.instance()的适配器方法编写的:

现在你可以写:

// if the order mattters, 
// then add promises sequentially.
Workqueue.transaction(function(queue) {
    var work1 = new Work();
    var work2 = new Work();
    return queue.add(work1)
    .then(function() {
        return queue.add(work2);
    });
});
// if the order doesn't mattter, 
// add promises in parallel.
Workqueue.transaction(function(queue) {
    var work1 = new Work();
    var work2 = new Work();
    var promise1 = queue.add(work1);
    var promise2 = queue.add(work2);
    return Promise.all(promise1, promise2);
});
// you can even pass `queue` around
Workqueue.transaction(function(queue) {
    var work1 = new Work();
    var promise1 = queue.add(work1);
    var promise2 = myCleverObject.doLotsOfAsyncStuff(queue);
    return Promise.all(promise1, promise2);
});
实际上,应该像这样包含错误处理程序-
Workqueue.transaction(function(){…}).catch(errorHandler)

无论编写什么,您所需要做的就是确保回调函数返回一个承诺,该承诺是所有组件异步(组件承诺)的集合。当聚合承诺解决时,处置方将确保交易已提交

和所有处理器一样,这台处理器也不能做任何你没有它做不到的事情。然而,它:

  • 通过提供命名的
    .transaction()
    方法,提醒您正在做什么
  • 通过将
    Workqueue.instance()
    约束为一次提交,强制执行单个事务的概念

如果出于任何原因,您需要在同一队列上执行两个或多个提交(为什么?),那么您可以始终恢复为直接调用
Workqueue.instance()

使用处理器模式:@BenjaminGruenbaum我不知道如何在这个问题中实现它。噢,哇!多么简单的解决方案啊。对于事务的真正含义来说,这是一个非常好的时刻。谢谢,我一直在努力实现同步性。我现在想到的实现是,事务应该是一个对象,应该向队列的客户端公开。客户机明确知道将工作添加到哪个事务中。是这样吗?这要看情况而定。如果希望在接口中使用单独的add()和commit()方法,那么可以。如果将addWorkAndCommit()作为一个方法,那么调用方就不需要了解任何事务。这是一个多么漂亮的解决方案!非常感谢。事务的概念应该扩展到界面的每一层吗?似乎当我有一个事务时,错误仍然存在。工作结果仍然可以是未定义的。嗯,不太确定。另一个解决方案是否存在同样的问题?我再次回顾这段代码,当Promise.resolve(work(queue))是“resolving”时,Promise.all(promise1,promise2)`已经完成了执行?它们并没有在提交过程中的某个时刻执行,对吗?没关系,我的错误,我需要刷新一下我的记忆。