skip to Main Content

I have a unique issue. Let’s say I have this code, which runs anonymously in a code block called a "Data Element" (Adobe Launch lingo). The code is assigned the name of the data element’s name so it can be referenced in the calling components which could happen 0 to 100s of times on a single page load:

return (function() {

    function main(var1, var2) {
        var thirdPartyResult = thirdpartyLibrary.someMethod(var1, var2);
        var returnVal = false;
        if (thirdPartyResult > 6) {
            returnVal = true;
        }
        return returnVal;
    }
    return main(cat, subCat);// these values are passed in from external source when data element is called.

})();

The above worked fine but I noticed timing issues because when the data element is called early in the page load (after cache clear etc.), the "thirdpartyLibrary" hasn’t loaded yet. So for example, the first 3 times it is called during the page loading, the data element throws and error because "thirdpartyLibrary" doesn’t exist yet, therefore I can’t use the output from it which is required. Regarding the code below which I know obviously doesn’t work, is syntactically wrong but expresses and conceptualizes what I would really want to do, I’d only like the main function delayed until the "thirdpartyLibrary" has loaded because my functionality in "main" depends on the "thirdpartyLibrary" but since I had to make the "main" function async, it returns a promise which has nothing to do with the data I want to return and will assign "promise pending" to my return statement ==> return main(’20’, ‘4’). I know I can’t do this: return await main(’20’, ‘4’) which would solve my issue or wrap my return in an async function because that wouldn’t be accessible. Any idea(s) on what I can possibly do?

return (function() {

    async function waitForLibrary() {
        return new Promise((resolve, reject) => {
            const maxAttempts = 8;
            const interval = 500; // milliseconds
            let attempts = 0;


            function checkLibrary() {
                if (typeof thirdpartyLibrary !== 'undefined' && typeof thirdpartyLibrary.someMethod === 'function') {
                    resolve();
                } else if (attempts < maxAttempts) {
                    attempts++;
                    setTimeout(checkLibrary, interval);
                } else {
                    reject(new Error("Timeout: Third-party library not loaded."));
                }
            }

            checkLibrary();
        });
    }

    async function main(var1, var2) {
        await waitForLibrary();
        var thirdPartyResult = thirdpartyLibrary.someMethod(var1, var2);
        var returnVal = false;
        if (thirdPartyResult > 6) {
            returnVal = true;
        }
        return returnVal;
    }
    return main(cat, subCat);// these values are passed in from external source when data element is called.

})();

Also I’m new to promises. Thanks!

2

Answers


  1. There are many things you could do, but you’re definitely taking a wrong route here.

    The junior-level solution here would be something like what you’re doing, but returning the actual promise and then in the rule action you don’t just blindly fire the server call. Instead, you carefully resolve your promise there and add the s.t() or s.tl() in the promise resolvation callback.

    The mid-level would be probably something like deploying a listener to the library load from the s code or from a page top rule, and then in that listener’s callback running a _satellite.track() or something like that to trigger the rules that rely on that lib. Basically what @trincot suggested.

    The senior-level solution is actually the simplest, but it’s also the best practice: make your front-end dev team defer the pageview dataLayer event (yes, EDDL is presumed here) until the library is loaded (in good implementation it’s just a matter of adding one promise into an array of promises analytics should wait for)

    But really, I’m giving these solutions as wildcards. They will work, but most likely, your whole approach should be changed completely to make the solution perfect. But for that, of course, we’d need to know what exactly you’re trying to wait for and why.

    This sounds to me like a consent-related issue where consent is governed by a third party library and this problem only affects the first pageview in a session since after that you’re just supposed to use cookies and not the library to gather existing consent. It’s typical and in these cases we normally have the consent action triggering the pageview when the consent doesn’t exist on the page load, so no need to wait for that lib to load whatever you do.

    Login or Signup to reply.
  2. It seems you want to ensure that thirdpartyLibrary is loaded before executing main. Since JavaScript is asynchronous by nature, you cannot transform an async function’s return value to a synchronous value directly.

    However, what you can do is:

    1. Make the caller aware of the asynchronous nature of your function and let the caller handle the Promise.
    2. Use an event system where you notify the caller once the value is ready.
    3. Cache the result once it’s fetched so subsequent calls can get the result synchronously if the library is loaded.

    If going with the first option, callers should be using async/await or .then() to handle the result. This will be a significant architectural change if the callers are not prepared to handle promises.

    Here’s a quick fix considering option 3: caching. Once the third-party library is loaded, cache the result. On subsequent calls, if the library is loaded, return the cached value.

    return (function() {
        let cachedResult = null; // To cache the result
    
        async function waitForLibrary() {
            // ... (same as your code)
        }
    
        async function main(var1, var2) {
            if (typeof thirdpartyLibrary !== 'undefined') {
                return cachedResult !== null ? cachedResult : processMain(var1, var2);
            }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search