Addon problem #1: sequence of promises

Assuming adequate permissions in the manifest file, why does the following notification code work when stepped through the debugger, but fails when running up to speed? I’m doing something wrong with promises, but I don’t know what.

// S: Promise to show string in notification box
function S(Msg,Title)
{
var p=browser.notifications.create({
“type”: “basic”,
“iconUrl”: browser.extension.getURL(“icons/link-48.png”),
“title”: Title,
“message”: Msg});
return p;
} // S

S(‘bg running 0’,‘Direct from bg’).then(s1).then(s2).catch(err);

function s1(val)
{
S(‘bg 1’,’’);
} // s1

function s2(val)
{
S(‘bg 2’,’’);
} // s2

function err(Msg)
{
console.log(’*** '+Msg);
throw Error;
} // err
// End

How does it fail? Which parts are executed, what error is shown etc.?

Tip: you can make code a lot more readable by putting it into a code block (``` or the </> button in the discourse editor).

I’ve also moved this topic to “Development” since it’s not support for a specific extension.

Thank you!

I apologize for leaving this out; I thought that it was short enough that people would try it out. I tend to leave things out when I’m anxious and frustrated with programming, which I normally love.

There are three calls here to create notification boxes, numbered 0, 1, and 2. These boxes should appear on the screen of the active tab, one after another. And they do appear if one steps through the code slowly in the debugger. But when run up to speed (by reloading the active tab, either with debugger showing or not), the notification boxes do not appear.

It seems obvious that the reason the notification function returns a promise is that it requires time to display a box because it is operating asynchronously. So, what is wrong with my code that doesn’t give it the time it needs to display?

Thank you for elaborating on what you’re seeing and what you’re expecting. You’re showing notifications with Firefox, so this is unrelated to the active tab. As the documentation for notification.create mentions:

If you call notifications.create() more than once in rapid succession, Firefox may end up not displaying any notification at all.

Which is the case here. Your s1 and s2 functions do not return their promises, which means these notification creations will be even faster than they would be if you waited for the respective promises. But even if you waited for the Promises afaik it’s not guaranteed that all notifications are shown.

Thank you. Yes, even after I return the promises in s1 and s2 the notifications still do not appear. Must be a bug in Firefox.

I wrote the following code to add a delay promise, but it doesn’t work. Can you please find my bug?

// Change setTimeout to a Promise
function delay(value,msec)
	{
	return new Promise(function(resolve)
		{
		var t=setTimeout(resolve.bind(null,value),msec);
		resolve.timerId=t;
		});
	} // delay

// S: Promise to show string in notification box
function S(Msg,Title,Callback)
	{
	browser.notifications.create({
		"type": "basic",
		"iconUrl": browser.extension.getURL("icons/link-48.png"),
		"title": Title,
		"message": Msg});
	return delay(500);
	} // S

S('bg 0','Bug 1').then(s1).then(s2).catch(err);

function s1(val)
	{
	return S('bg 1','Bug 1');
	} // s1

function s2(val)
	{
	return S('bg 2','Bug 1');
	} // s2

Even this minimal code using my delay() doesn’t do anything!

console.log('before');
delay(0,1000).then(p1);

function p1()
	{
	console.log('after');
	} // p1

When I fix the obvious bug, Bug 1 now works with a 1 second delay after each notification!

Thank you for your help. But why does the console.log example fail? The log entries do not show up in the background debugger.

This code you’ve posted works for me :slight_smile:. I’ve just executed it in the console here.
There is probably some error before that code… check also browser console for errors - browser console is a special console, you can open it with Ctrl + Shift + J.

Also your timeout promise looks a bit complicated, you use a simpler one:

const timeoutPromise = delay => new Promise(resolve => setTimeout(resolve, delay));

There is no other code. But your “simpler” function just seems to omit the bind, and it will not run on all browsers because of the ES6 syntax. I think you are saying

const timeoutPromise = function(delay)
	{
	new Promise(function (resolve)
		{setTimeout(resolve, delay);}
	});

Please let me know if this has bugs; I don’t use the latest syntax until almost all browsers in use support it , especially for extensions/addons.

Here is the delay function, as corrected, in case anyone else needs it:

// Change setTimeout to a Promise
function delay(msec)
	{
	return new Promise(function(resolve)
		{
		setTimeout(resolve,msec);
		});
	} // delay

All browsers that will support webextensions will also support that syntax. No need to avoid ES6 in extensions. Further the bind is unnecessary.

In your snippet you are once again not returning the Promise.

1 Like

I think the reason that bind is not necessary is that we don’t care what value is in “this”. That is the main reason for using bind, for making sure “this” is correct.

Exactly, resolve doesn’t care about the this at all and takes exactly one parameter.