Asynchronous Nature in Cypress

Cypress is built on node.js server and it works with Javascript programming
language. Anything which is dependent on node.js is asynchronous in nature and
so Cypress commands work in that mode.
When we have a group of test steps in a test case, all the steps start executing in
parallel without waiting for the previous step to complete. In a synchronous
execution, each test step runs in sequence and we move to the next step only if the
previous step execution is done.
Thus in asynchronous execution like Cypress, each test step is independent to each
other even though the test steps are designed in a sequential order. In short, in an
asynchronous mode each step does not take into account the result or state of the
previous step execution and simply runs every steps.
Cypress has come up with a wrapper which makes sure that test execution of its
commands happen in sequence in which they are developed. Thus these
commands are executed all at once but they are queued. However if a Javascript
command works along with a Cypress command, it remains asynchronous.
Now let us execute a Cypress code −
// test suite
describe('Tutorialspoint Test', function () {
   // test case
   it('Test Case1', function (){
      // test step to launch a URL
      cy.visit("https://www.tutorialspoint.com/index.htm");
      // enter test in the edit box
      cy.get('#gs_50d > tbody > tr > td'). should('have.length',2);
      // locate element with get and find method
      cy.get('#gs_50d > tbody > tr > td'). find('input')
      //enter test in the edit box
      .type('Cypress');
      console.log('Tutorialspoint');
   });
});
On triggering the above code for execution, if we open the browser console, we will find Tutorialspoint printed on it even before the browser is loaded. This confirms the fact that console.log test step did not wait for other test steps and prints immediately in console.
Thus we see that since console.log is a Javascript command it doesn't queue itself like a Cypress compound and carries on with its execution. Cypress executes its steps serially with the help of promise handling.
A promise is a programming language that determines the state of a Cypress
command. There are three types of promise states as listed below −
Resolved − This is the state if the test step executes without failure.
Resolved − This is the state if the test step executes without failure.
Pending − This is the state if the test step execution result is being awaited.
Pending − This is the state if the test step execution result is being awaited.
Rejected − This is the state if the test step executes with failure.
Rejected − This is the state if the test step executes with failure.
The following command in Cypress gets executed only after the previous command or promise response is resolved. We can implement promise in our Cypress code with the help of then() method.
The code below describes the promise implemented in Javascript for each Cypress
compound. This implementation makes a code dirty and lengthy.
// test suite
describe('Tutorialspoint Test', function () {
   // test case
   it('Test Case1', function (){
      return cy.visit('https://www.tutorialspoint.com/index.htm')
      .then(() => {
         return cy.get('.product');
      })
      .then(($element) => {
         return cy.click($element);
      })
   })
})
Cypress handles promises internally and resolves them with the help of wrappers
and we can implement our code without taking into account the promise states.
Thus the code readability increases to a large extent.
The above code in Cypress without promise.
// test suite
describe('Tutorialspoint Test', function () {
   // test case
   it('Test Case1', function (){
      cy.visit('https://www.tutorialspoint.com/index.htm')
      cy.get('.product').click();
   })
})
Thus Cypress takes into account that the next step in a test case shall execute only
if the prior command or promise is in resolved state.