Return a promise from an artist function?

An attempt to interact with the JS API, but the Grunt task failed; I think my logic is confused. My steps:

  • get tokens from a file, check them ( check_tokens )
  • if they are old - refresh them ( refresh_tokens )
  • call the API to update, if it fails - get new ( authorize_with_api ) <- this is a problem
  • from authorize_with_api reject with error or allow using tokens

The Grunt task currently reports UnhandledPromiseRejectionWarning and never completes. If I comment on the call to authorize_with_api , it will complete correctly with an error, and I will get my topmost message caught error! .

Why can't I return a promise from an artist function? What is wrong with my logic?

 /* global sdk, config, tokens */ return getTokens().then((p_tokens) => { tokens = p_tokens; return check_tokens(tokens); }).then((tokens) => { console.log('then() is called!'); }).catch((err) => { console.error('caught error!', err); }); function check_tokens(tokens) { if(are_old(tokens)) { // returns true return refresh_tokens(tokens); } return Promise.resolve(tokens); } function refresh_tokens(tokens) { return new Promise(function(resolve, reject) { sdk.refreshTokens(tokens.refresh_token, function(err, new_tokens) { if(err) { if(error.code === 'invalid_grant') { return authorize_with_api(); } reject('refreshTokens failed'); } else if(newTokens) { resolve(new_tokens); } }); }); } function authorize_with_api() { return new Promise(function(resolve, reject) { sdk.getTokens(config.auth_code, function(err, tokens) { if(err) { reject('getTokens failed'); } else if(tokens) { resolve(tokens); } }); }); } 
+6
source share
1 answer

Returning from the Promise constructor (or any function inside it) does not resolve the promise:

 return new Promise(function(resolve, reject) { sdk.refreshTokens(..., function(err, new_tokens) { if(error.code === 'invalid_grant') { return authorize_with_api(); } // ^--- this will not chain to the promise being created. 

Even if you did not have a return from the sdk.refreshTokens and instead had a direct return authorize_with_api() without a callback, the result would still not get the chain.

To resolve a promise, you cannot return from your constructor, but you must explicitly call one of the given callbacks (allow / reject):

 return new Promise(function(resolve, reject) { sdk.refreshTokens(..., function(err, new_tokens) { if(error.code === 'invalid_grant') { resolve(authorize_with_api()); } // ^--- must call resolve here 

The resolution of the promise actually also eliminates the rejection, so regardless of whether authorize_with_api is allowed or rejected, the state will appropriately distribute the chain.

My suggestion is to still support the return order to support the alleged visual semantics of forming the if branch, early return, but the code will work without it, because promises can only be resolved once, and all further reject / resolve calls are ignored .

 return new Promise(function(resolve, reject) { sdk.refreshTokens(..., function(err, new_tokens) { if(error.code === 'invalid_grant') { return resolve(authorize_with_api()); } // ^--- should still return here for readability - clean logic purposes reject('refreshTokens failed'); // this will be ignored if the above 'resolve' gets called first, no matter if you have the 'return' statement 

Examples:

 function success() { return Promise.resolve('success'); } function error() { return Promise.reject('error'); } function alwaysPending() { return new Promise(() => { return success(); }); } function resolves() { return new Promise((resolve) => { resolve(success()); }); } function rejects() { return new Promise((resolve) => { resolve(error()); }); } alwaysPending().then(console.log); // doesn't log anything resolves().then(console.log); rejects().catch(console.log); 
+9
source

Source: https://habr.com/ru/post/1262364/


All Articles