I'm working on an async script loader using bluebird and I'm struggling to pass an error up to where I can catch it.
When a file is loaded I'm calling my method named declare
like this:
declare("storage", [
{"name": 'util', "src": '../src/util.js'}
], function (util) {
var storage = {};
//...stuff with util
return storage;
});
With declare
being:
declare = function (name, dependency_list, callback) {
var resolver;
// digest promises returned for each module
function digestDependencyArray(my_dependency_array) {
var i, len, response_array;
len = my_dependency_array.length;
for (i = 0, response_array = []; i < len; i += 1) {
response_array[i] = my_dependency_array[i];
}
return Promise.all(response_array);
}
// resolve request promise
function resolveDependencyArray(my_fullfillment_array) {
var return_value = callback.apply(window, my_fullfillment_array);
// window.exports must be used when integrating commonjs modules
if (!return_value) {
return_value = window.exports;
}
resolver(return_value);
}
// START: set callback to (resolved) callback or new promise
my_lib.callback_dict[name] = my_lib.callback_dict[name] ||
new Promise(function (resolve) {
resolver = resolve;
if (dependency_list.length === 0) {
return resolver(callback.apply(window));
}
return request(dependency_list)
.then(digestDependencyArray)
.then(resolveDependencyArray)
// DON'T CATCH HERE...
.catch(console.log);
});
};
This all works fine except I would like to not have the catch
statement at this point, because the error handling should be done in a different module (the console.log is just a flag).
Question:
How would I propagate an error occuring in my declare
method to a higher promise chain? I had hoped adding a catch
handler on my declare
calls would help, but this breaks the whole script - I assume because I'm returning the module from my declare call vs a valid promise response.
Thanks for any tips!
EDIT:
I'm calling declare from this:
request([{"name": "foo", "src": "path/to/foo.js"}])
.spread(foo) {
})
.catch(function (e) {
console.log(e);
})
request
will load the file inside a promise which gets resolved when the file is loaded and run the file content as callback, which then calls the above declare
method. Somehow my error is lost on the way (code here). Let's see if I can catch
it somewhere...
Edit 2:
Changing to this inside declare:
function resolveDependencyArray(my_fullfillment_array) {
var return_value = callback.apply(window, my_fullfillment_array);
if (!return_value) {
return_value = window.exports;
}
return return_value;
}
function handler() {
if (dependency_list.length === 0) {
Promise.resolve(callback.apply(window));
} else {
return request(dependency_list)
.then(digestDependencyArray)
.then(resolveDependencyArray)
.catch(function (e) {
reject(e);
});
}
}
clappjs.callback_dict[name] = clappjs.callback_dict[name] || handler();
While I get no errors, requesting multiple modules does not work because modules are returned undefined
, so:
request(["foo", "bar", "baz"]).spread(function (foo, bar, baz) {
console.log(foo); // undefined
console.log(bar); // {} OK
console.log(baz); // undefined
});
versus a new Promise
properly returning the file once it's loaded.
catch " around the executor automatically catches the error and turns it into rejected promise. This happens not only in the executor function, but in its handlers as well. If we throw inside a . then handler, that means a rejected promise, so the control jumps to the nearest error handler.
If an error condition arises inside a promise, you “reject” the promise by calling the reject() function with an error. To handle a promise rejection, you pass a callback to the catch() function. This is a simple example, so catching the rejection is trivial.
So failing to resolve or reject a promise just fails to ever change the state from "pending" to anything else. This doesn't cause any fundamental problem in Javascript because a promise is just a regular Javascript object.
catch() The catch() method returns a Promise and deals with rejected cases only. It behaves the same as calling Promise.
You need to rethrow the error!
.catch(function(e) {
console.log(e); // calling it as a method, btw
throw e;
})
You also might try to use tap
, or return the promise that you have in the chain before adding .catch(console.log)
.
Also, you are using the manually-construct-promise antipattern, while you actually should never need to call the Promise
constructor. Just use the promise that you already have! It seems that you want to do this:
my_lib.callback_dict[name] = my_lib.callback_dict[name] || (
dependency_list.length === 0
? Promise.resolve()
: request(dependency_list)
.then(digestDependencyArray)
.then(resolveDependencyArray) // don't call a global `resolver()`
// just `return` the value!
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With