fullstorydev / fullstory-browser-sdk

Official FullStory SDK for JavaScript, for web browsers
MIT License
55 stars 17 forks source link

Provide a way to defer execution of certain API functions until FullStory is bootstrapped #2

Open patrick-fs opened 5 years ago

patrick-fs commented 5 years ago

Use a promise-based contract to let integrators know when FullStory is fully bootstrapped:

FullStory.isReady().then(() => {});

or

await FullStory.isReady();
// do more things

OR

use a callback interface for functions that need to wait until FullStory is bootstrapped to become operational: asyncGetCurrentSessionURL(callback, now?)

patrick-fs commented 4 years ago

Thoughts on implementation:

isReady() with a promise

let alreadyReady = () => {};
// test to see if window['_fs_ready'] has already been set in the <head> of the document
if (typeof window._fs_ready === 'function') {
  alreadyReady = window._fs_ready;
} 

let readyCalled = false;
window._fs_ready = () => {
  readyCalled = true;
  alreadyReady();
};

export const isReady = new Promise((resolve, reject) => {
  if (readyCalled) return resolve();
  let iteration = 0;
  const id = setInterval(() => {
    if (readyCalled) {
      clearInterval(id);
      return resolve();
    }
    iteration++;
    if (iteration > 10) {
      clearInterval(id);
      return reject('timeout');
    }
  }, 500);
});

async functions with a callback

There's no general isReady() function, rather individual functions that need to wait for FullStory to bootstrap before they become operational have an async{function name} version.

let alreadyReady = () => {};
// test to see if window['_fs_ready'] has already been set in the <head> of the document
if (typeof window._fs_ready === 'function') {
  alreadyReady = window._fs_ready;
} 

let readyCalled = false;
window._fs_ready = () => {
  readyCalled = true;
  alreadyReady();
};

const waitReady = (cb) => {
  if (readyCalled) return cb();
  let iteration = 0;
  const id = setInterval(() => {
    if (readyCalled) {
      clearInterval(id);
      return cb();
    }
    iteration++;
    if (iteration > 10) {
      clearInterval(id);
      throw new Error('timeout');
  }, 500);
}

const export asyncGetCurrentSessionURL(callback, now) {
  const cb = () => {callback(getCurrentSessionURL(now))};
  waitReady(cb);
}
patrick-fs commented 4 years ago

Question: is there a use case where a client of the FullStory browser API cares whether FS is ready other than waiting to get a session replay url (or session replay id)?

@bddean would love to know your thoughts.

bddean commented 4 years ago

@patrick-fs Sorry, I kept forgetting to reply to this message. No, those are the only two cases, though I can imagine we might want to add more in the future.

Relatedly, here's a PR that adds a callback-based variant to the snippet itself (can't use promises because browser support): https://github.com/cowpaths/mn/pull/19589