Search code examples
javascriptpromisewinjsvisual-studio-lightswitchwinjs-promise

Why does one method of stacking promises in Lightswitch work when another doesn't?


I'm working with a Lightswitch 2015 application for tracking customer satisfaction interviews. I'm trying to create a function that will create a new interview, populate a few items, then save it to the database, and open it for editing in a new window. I'm struggling with understanding the behavior of promises in this context.

I have these three blocs of code:

1)

myapp.Interviews_Management.AddInterview_Tap_execute = function (screen)
{
    var NewInterview = screen.Interviews.addNew();
    NewInterview.c_Date = screen.InterviewDate;
    NewInterview.Participant = screen.Interviewee;
    NewInterview.Location = screen.InterviewFocusLocation;
    screen.closePopup()
    .then(() =>
    {
        myapp.applyChanges()
                .then(() =>{ myapp.showInterview_AddEdit(NewInterview); });
    }, (error) =>{ msls.showMessageBox(error.toString()); });
};

2)

myapp.Interviews_Management.AddInterview_Tap_execute = function (screen)
{
    var NewInterview = screen.Interviews.addNew();
    NewInterview.c_Date = screen.InterviewDate;
    NewInterview.Participant = screen.Interviewee;
    NewInterview.Location = screen.InterviewFocusLocation;
    screen.closePopup()
        .then(myapp.applyChanges()
            .then(myapp.showInterview_AddEdit(NewInterview),
                (error) =>{ msls.showMessageBox(error.toString()); })
            );
};

3)

myapp.Interviews_Management.AddInterview_Tap_execute = function (screen)
{
    var NewInterview = screen.Interviews.addNew();
    NewInterview.c_Date = screen.InterviewDate;
    NewInterview.Participant = screen.Interviewee;
    NewInterview.Location = screen.InterviewFocusLocation;
    screen.closePopup()
        .then(myapp.applyChanges())
        .then(myapp.showInterview_AddEdit(NewInterview),
            (error) =>{ msls.showMessageBox(error.toString()); });
};

1 works as expected; that is, creates a new interview, populates the fields, and opens an edit window. However, I'm concerned that errors thrown from inside the lambda function(s) won't be properly passed to the external context.

2 and 3 both create a new interview and populate the fields, but then throws an error saying, "This action cannot be taken while screen is navigating.", which seems to suggest it is not waiting for each promise to fulfill before attempting to execute the next one. 3 also seems like perhaps it is wrapping promises in other promises, which may again lead to not properly passing any thrown errors outward (and, I hear, is a pretty common anti-pattern for people struggling with understanding promises?).

Can someone help me understand what exactly is going on here? I've been struggling generally with proper best practice in nesting promises or using a series of promises; any help with proper way of handling this would be much appreciated!


Solution

  • You always need to pass a callback function to then, not the result of calling it immediately.

    You want

    screen.closePopup()
      .then(myapp.applyChanges) // or () => myapp.applyChanges()
      .then(() => myapp.showInterview_AddEdit(NewInterview)),
      .catch(error => { msls.showMessageBox(error.toString()); });
    

    For why that catch is necessary (better than using the second then parameter), see When is .then(success, fail) considered an antipattern for promises?.