Should synchronous code called by Promise .then cr

2020-08-19 16:29发布

问题:

I've implemented some code, where asynchronous code is followed by some synchronous functions. For example:

function processSomeAsyncData() {
  asyncFuncCall()
    .then(syncFunction)
    .catch(error);
}

If I understand correctly then is also a Promise. Then, should I create a promise in the synchronous code as well?

function syncFunction() {
  const p = new Promise (function (resolve, reject) {
    //Do some sync stuff
    ...
    resolve(data);
  }
  return p;
}

If that isn't necessary, how do you reject the promise from the synchronous code if an error occurred?

回答1:

You don't need to create a new promise explicitly. There is an easier way.

This example is contrived because it will never fail, but the point is that you don't have to create a promise and you don't have to return a resolve(val).

function syncFunction() {
  var j = "hi"
  if(j){
    return j;
  }
  return new Error('i am an error');
}

This will work:

asyncFunction()
  .then(syncFunction);

But if you did it the other way around:

syncFunction()
  .then(asyncFunction);

You would have to define your syncFunction as:

function syncFunction() {

  var j = "hi"
  return new Promise((resolve, reject) => {
    if(j){
      return resolve(j);
    }
    return reject('error');
  })  
}

Edit: To prove to all you non believers out there, give this guy a shot locally on your computer. Proves that you have these many options available to you. :)

var Promise = require('bluebird');


function b(h) {
    if(h){
        return h;
    }
    return Promise.resolve('hello from b');
}

function a(z) {
    return new Promise((resolve, reject)=> {
        if(z){return resolve(z)};
        return resolve('hello from a');
    })
}

a().then(b).then(x => console.log(x)).catch(e => console.log(e));
b().then(a).then(x => console.log(x)).catch(e => console.log(e));


回答2:

No. Synchronous functions may be called from synchronous code and should always fail synchronously! They need not conform to asynchronous callers in any way. If an error occurs just throw an error. Try it:

var asyncFuncCall = () => Promise.resolve();

function syncFunction() {
  throw new Error("Fail");
}

asyncFuncCall()
  .then(syncFunction)
  .catch(e => console.log("Caught: " + e.message));

This works because an exception thrown by a function passed to a .then is converted to a rejection of the promise it is supposed to return.

Additionally, any value returned by a function passed to a .then is converted to a promise resolved with that value. The promise code calling the function takes care of this.

This lets you mix synchronous and asynchronous code without problems:

asyncFuncCallOne()
  .then(() => {
    var x = syncFunction();
    return asyncFuncCallTwo(x);
  })
  .catch(e => console.log(e.message));


回答3:

It's optional.

If you return a promise from the syncFunction, then your original promise will resolve only after the new promise resolves and any value returned by the new promise will be passed to the next then in the chain.

If you return a non-Promise value, that will be passed to the next then in the chain.

To reject from within syncFunction, just throw an exception.