简体   繁体   English

javascript中的异步事务

[英]Async transactions in javascript

First of all rollback is something that I do not care about. 首先回滚是我不关心的事情。

I would like to be able to lock a sequence of async functions/promises/tasks (let's call it a "transaction") with a name/id (or array of names), so that they happen in sequence, and so that any other "transaction" with the same name(s) that are run by another part of the system are delayed from starting until the running transaction using the same name(s) has completed. 我希望能够使用名称/ id(或名称数组)锁定一系列异步函数/ promises / tasks(让我们称之为“事务”),以便它们按顺序发生,以便任何其他具有由系统的另一部分运行的相同名称的“事务”从开始延迟到使用相同名称的运行事务完成。 So it basically is queueing the sequences of async tasks, or "transaction"s. 所以它基本上是排队异步任务或“事务”的序列。

Here is some example code of the situation: 以下是一些示例代码:

function a()
{
  // do stuff
  return new Promise(/*...*/);
}


function b()
{
  // do stuff
  return new Promise(/*...*/);
}



function c()
{
  // do stuff
  return a.then(() => b());
}

Now at any time the system could call a , b , or c , and when it does I don't want c and b running at the same time, but obvious c depends on b . 现在系统可以随时调用abc ,当它发生时,我不希望cb运行,但明显的c取决于b

I've been looking for a package on npm to help with this but I haven't found anything, I wonder if anyone can suggest something that I might have missed that would help with this? 我一直在寻找npm的包来帮助解决这个问题,但是我还没有找到任何东西,我想知道是否有人可以提出一些我可能会错过的东西,这会对此有所帮助?

I think gulp tasks can help you out of the box. 我认为gulp任务可以帮助您开箱即用。 This guarantees that c always run after b and so b after a 这保证了c总是后运行bba

const gulp = require('gulp');
gulp.task('a', done => {
  // do stuff
  console.log('a');
  done();
});

gulp.task('b', ['a'], done => {
  // do stuff
  console.log('b');
  done();
});

gulp.task('c', ['b'], done => {
  // do more stuff
  console.log('c');
  done();
});

gulp.start('c'); // Logs a, b, c

Try it! 试试吧!

You could write your own little transaction manager. 你可以编写自己的小事务管理器。

const transactions = {};

function doTransaction(name, promiseFunc) {
  transactions[name] = (transactions[name] || Promise.resolve()).then(promiseFunc);
}

Use async/await and have babel transpile it. 使用async / await并让babel转发它。 Async Babel Docs Async Babel Docs

function a()
{
  // do stuff
  return new Promise(/*...*/);
}


async function b()
{
  const aData = await a();
  // do stuff
  return new Promise(/*...*/);
}



async function c()
{
  const bData = await b();
  // do stuff
  return bData;
}

You can go for https://github.com/Reactive-Extensions/RxJS 你可以去https://github.com/Reactive-Extensions/RxJS

They have many functions to handle single/multiple/dependent/parallel async calls. 它们具有许多功能来处理单/多/从属/并行异步调用。

function a()
{
  // do stuff
  return new Promise(/*...*/);
}

function b()
{
  // do stuff
  return new Promise(/*...*/);
}

function c()
{
  // do stuff
  return new Value;
}

a().then(function(data_a) {
  // you can make use of return value (which is data_a) here or as an argument for function b or even function c
  b().then(function(data_b) {
    // you can make use of return value (which is data_b) here or as an argument for function c
    c().then(function(data_c) {
      // do your coding here
    });
  });
});

you can check this link for reference : https://spring.io/understanding/javascript-promises 您可以查看此链接以供参考: https//spring.io/understanding/javascript-promises

Ok, here's my take. 好的,这是我的看法。 You use a wrapper for your function b which returns and object with 2 methods: doCall and wait . 您为函数b使用包装器,它使用2种方法返回和对象: doCallwait The wrapper should be called only once. 包装器应该只调用一次。

doCall will call your function and trace its completion for the wait() function. doCall将调用您的函数并跟踪wait()函数的完成情况。

wait() will wait for the completion and always resolve when doCall() finishes wait()将等待完成,并在doCall()完成时始终解析

Now for the code, also on CodePen (see developer console): 现在代码,也在CodePen上 (参见开发者控制台):

 function wrapPromiseFn(fn) { var prev = null; var doCall = function() { var retValue; prev = new Promise(function(resolve, reject) { retValue = fn(); retValue.then(function(result) { resolve(true); }); retValue.catch(function(result) { resolve(true); }); }); return retValue; }; var wait = function() { return prev ? prev : Promise.resolve(false); }; return { doCall: doCall, wait: wait }; } function a() { return Promise.resolve(42); } function b() { //return Promise.reject(new Date()); return Promise.resolve(new Date().getTime()); } var wrappedB = wrapPromiseFn(b); function doStuff() { return wrappedB.wait().then(function(didWait) { return a().then(function(_a) { return wrappedB.doCall().then(function(_b) { console.log("didWait, a, b: ", didWait, _a, _b); }); }); }); } //run it twice to prove it did wait doStuff().then(doStuff) 

It proves the concept, of course it would need some polish to pass arguments from doCall to the wrapped function. 它证明了这个概念,当然需要进行一些修改才能将参数从doCall传递给包装函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM