简体   繁体   中英

Linking promise chains

I have a working promise chain:

function startSync(db) {
  var promise = new Promise(function(resolve, reject) {

    syncCats(db)
      .then(syncTrees(db))
      .then(syncCars(db))
      ...  
      .then(resolve());
  });
return promise;
}

This works great. It performs each of those function calls, waiting for each one to complete before firing off another. Each of those functions returns a promise, like so:

function syncCaesar(db) {
  var promise = new Promise(resolve, reject) {
    // do aysnc db calls, and whatnot, resolving/rejecting appropriately
  }
return promise;
}

I need to run this chain on a series of databases, sequentially. I've tried other solutions here, but they would fire off syncCats() all at once.

For instance:

var promise = Promise.resolve();
dbs.forEach(function(db) {
  promise = promise.then(startSync(db));
}

Fires off syncCats(db[0]) and syncCats(db[1]) simultaneously.

Edit:

Performing startSync(dbs[0]).then(startSync(dbs[1])); acts the same.

Edit2: Also performs the same:

dbs.forEach(function(db) {
  promise = promise.then(function() {
    return startSync(db);
  }
}

You're calling startSync and then passing its return value in to then . So naturally, if you do that twice, it's going to start the process twice in parallel.

Instead, pass in a function that doesn't call startSync until it's called:

var promise = Promise.resolve();
dbs.forEach(function(db) {
  promise = promise.then(function() { startSync(db); });
});

or with ES2015:

let promise = Promise.resolve();
dbs.forEach(function(db) {
  promise = promise.then(_ => startSync(db));
});

Separately, three things jump out about startSync :

  1. It starts all its operations in parallel, not sequentially
  2. It exhibits the promise creation anti-pattern . There's no reason for startSync to create a new promise; it already has a promise it can work with
  3. It ensures that its resolution value is undefined

If you really want the operations running in parallel like that, I suggest being more explicit about it:

function startSync(db) {
  return Promise.all([
    syncCats(db),
    syncTrees(db),
    syncCars(db)
  ])
  .then(_ => undefined); // This does #3
}

...but you could also do to avoid the anti-pattern:

// Still run in parallel!
function startSync(db) {
  return syncCats(db)
    .then(syncTrees(db))
    .then(syncCars(db))
    .then(_ => undefined); // Does #3
}

If you meant for them to be sequential, you need to pass functions, not the result of calling them:

function startSync(db) {
  return syncCats(db)
    .then(_ => syncTrees(db))
    .then(_ => syncCars(db))
    .then(_ => undefined);  // Again, does #3
}

If you made syncCats , syncTrees , and syncCars resolve their promises with db , like this:

function syncCats(db) {
    return startSomethingAsync().then(_ => db);
}

...then it could be:

function startSync(db) {
  return syncCats(db)
    .then(syncTrees)
    .then(syncCars)
    .then(_ => undefined);  // Only here for #3
}

...since each would receive db as its first argument.

Finally, if you don't need to force undefined as the promise resolution value, I suggest dropping that part from the above. :-)

With appreciation to TJ and Jaromanda, I was able to solve it by fixing how startSync() was resolved:

function startSync(db) {
  var promise = new Promise(function(resolve, reject) {

   syncCats(db)
      .then(syncTrees(db)) // not correct way to call, see below
      .then(syncCars(db))
      ...  
      .then(function() { resolve(); });
  });
 return promise;
}

Now, as TJ points out, the way each of the .then 's is being called is incorrect. He explains it better in his answer. I'm being saved by some misunderstood database layer queueing. syncTrees() and syncCars() should be running in parallel.

If I understood it correctly, you will be having an array of databases and you want to sync them one by one ie sync for dbs[0], once that is complete sync for dbs[1], and so on. If that's correct you can do something like this.

var syncMultipleDBs = (dataBases) {
    var db = dataBases.shift();
    if (!db) {
        return;
    }
    startSync(db).then(syncMultipleDBs.bind(null, dataBases));
};

syncsyncMultipleDBs(dbs.slice());

I hope this will help.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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