Joseph Kirtman
Joseph Kirtman

Reputation: 401

Chain promises calls

I need a consecutive execution of these three

return App.initAccount().then(App.bindEvents).then(App.render);

whereas App.initAccount():

  initAccount: async function() {

    console.log('Initializing account...');

    await web3.eth.getCoinbase(function(err, account) {
      if (err !== null) {
        throw err;
      }

      App.account = account;
      console.log('Account: ' + App.account);
    });
  }

and App.bindEvents(), App.render() just ordinary synchronous functions. But what I've got in a console:

Initializing account...
Binding events
Rendering
Account: ***

Please, explain, how to chain these calls in order to wait until the asynchronous function is returned

UPD. According to the documentation I thought web3.eth.getCoinbase() returns a Promise<\String>, but turned out that wasn't correct.

Upvotes: 1

Views: 266

Answers (4)

antoinechalifour
antoinechalifour

Reputation: 495

I suppose web3.eth.getCoinbase() does not return a promise (so you are not awaiting anything here. You need to wrap the function call in a promise like this :

await new Promise((resolve, reject) => {
  web3.eth.getCoinbase(function(err, account) {
      if (err !== null) {
        return reject(err)
      }

      App.account = account;
      return resolve(account)
    });
})

Edit based on T.J suggestion

In this case, you don't actually need initAccount to be an asynchronous function, you can refactor your function to be :

initAccount: function() {
  return new Promise((resolve, reject) => {
    console.log('Initializing account...');

    web3.eth.getCoinbase(function(err, account) {
      if (err !== null) {
        return reject(err)
      }

      App.account = account;
      console.log('Account: ' + App.account);
      return resolve(account)
    });
  })
}

Upvotes: 2

Evan Trimboli
Evan Trimboli

Reputation: 30092

From a style standpoint, you're best off not mixing callbacks and async/await in terms of sequential flow. To use callback style functions and weave them in with async/await, you can wrap them in promises to "hide" the promises away:

class Foo {
    initAccount() {
        return new Promise((resolve, reject) => {
            web3.eth.getCoinbase(function(err, account) {
                if (err !== null) {
                    reject(err);
                }
                resolve(account);
            });
        });
    }
}

const o = new Foo();
const account = await foo.initAccount();
// Then do bindEvents
// etc

Upvotes: 1

T.J. Crowder
T.J. Crowder

Reputation: 1075527

I suspect web3.eth.getCoinbase doesn't return a promise, since you're passing a callback to it. await only awaits promises.

So you probably need to wrap that API in a promise, which means that initAccount wouldn't need to be an async function as this is one of the rare situations where you need new Promise:

initAccount: function() {
  return new Promise((resolve, reject) => {
    console.log('Initializing account...');

    web3.eth.getCoinbase(function(err, account) {
      if (err !== null) {
        reject(err);
      } else {
        App.account = account;
        console.log('Account: ' + App.account);
      }
    });
  });
}

Separately, if bindEvents and render do their work synchronously, you'd usually put them in the same then handler:

return App.initAccount().then(() => {
  App.bindEvents();
  App.render();
});

Upvotes: 0

Axnyff
Axnyff

Reputation: 9964

getCoinbase does not look like a function returning a promise. You should wrap it to behave as expected.

Either manually:

await new Promise((resolve, reject) => {
  web3.eth.getCoinbase(function(err, account) {
    if (err !== null) {
      reject(err);
    }

    App.account = account;
    console.log('Account: ' + App.account);
    resolve(account);
  });
});

Or using something like this

Upvotes: 0

Related Questions