Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

Today we’ll review the use of promise’s chained calls to solve sequential asynchronous operations.

Promise chain call

The most commonly used chained invocation in JS is the jQuery framework, as shown in the following code

$('.level1').click(function () {$(this)
    .next()
    .stop()
    .slideToggle()
    .parent()
    .sibling()
    .children('ul')
    .slideUp();
});
Copy the code

The instance methods of the Promise object then(), catch(), and finally() actually return a Promise object.

Therefore, instance methods such as THEN () can be continuously called on the returned Promise object, which is called the promise chain.

Here’s a simple example

Create a Promise object that successfully returns the number 10 after 3 seconds.

let p = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve(10);
  }, 3 * 1000);
});

p.then((result) = > {
  console.log(result);
  return result * 2;
});
// Output after 3 seconds:
/ / 10
Copy the code

Inside the THEN () callback I return a new value result * 2, because THEN returns a new Promise object equal to the value of resolve. So you can continue calling the then method, as follows

let p = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve(10);
  }, 3 * 1000);
});

p.then((result) = > {
  console.log(result);
  return result * 2;
}).then((result) = > {
  console.log(result);
  return result * 3;
});

// Output after 3 seconds:
/ / 10
/ / 20
Copy the code

And it can go on and on

let p = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve(10);
  }, 3 * 1000);
});

p.then((result) = > {
  console.log(result);
  return result * 2;
}).then((result) = > {
  console.log(result);
  return result * 3;
}).then((result) = > {
  console.log(result);
  return result * 4;
});

// Output after 3 seconds:
/ / 10
/ / 20
/ / 60
Copy the code

More then

Instead of using chained calls, multiple then methods are called simultaneously on a promise

let p = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve(10);
  }, 3 * 1000);
});

p.then((result) = > {
  console.log(result); / / 10
  return result * 2;
})

p.then((result) = > {
  console.log(result); / / 10
  return result * 3;
})

p.then((result) = > {
  console.log(result); / / 10
  return result * 4;
});

// Output after 3 seconds:
/ / 10
/ / 10
/ / 10
Copy the code

In the example above, one Promise object, multiple THEN’s, none of which are related to each other. They are executed independently, not like the chain calls above.

In a real project, you would rarely call multiple THEN methods on a promise like this.

return new promise

We return a value in the then callback, which is equivalent to new a promise and reslove the value immediately.

So it looks like this

let p = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve(10);
  }, 3 * 1000);
});

p.then((result) = > {
  console.log(result);
  return new Promise((resolve, reject) = > {
    setTimeout(() = > {
      resolve(result * 2);
    }, 3 * 1000);
  });
}).then((result) = > {
  console.log(result);
  return new Promise((resolve, reject) = > {
    setTimeout(() = > {
      resolve(result * 3);
    }, 3 * 1000);
  });
}).then(result= > console.log(result));

// Output every 3 seconds:
/ / 10
/ / 20
/ / 60
Copy the code

Next, we can wrap a function that returns a promise

/ / promise
function generateNumber(num) {
  return new Promise((resolve, reject) = > {
    setTimeout(() = > {
      resolve(num);
    }, 3 * 1000);
  });
}

generateNumber(10)
  .then(result= > {
    console.log(result);
    return generateNumber(result * 2);
  })
  .then((result) = > {
    console.log(result);
    return generateNumber(result * 3);
  })
  .then(result= > console.log(result));

// Output every 3 seconds:
/ / 10
/ / 20
/ / 60
Copy the code

As with the result above, we make a wrapper with the generateNumber function.

Promise chain syntax

In JS development, we often encounter the need to perform multiple asynchronous tasks in sequence. The next asynchronous task depends on the result of the previous asynchronous task. Without the promise, this would be the case with callback

Get('/user'.function(user) {
  Get(`/level/${user.id}`.function(level) {
    Get(`/info/${level.id}`.function(info) {
      console.log(info)
    })
  })
})
Copy the code

Use the Promise chain call

getUser()
  .then(result= > getLevel(result))
  .then(result= > getInfo(result))
  ...
Copy the code

It looks a lot cleaner than the callback method, which is infinitely nested, with promises just continuing down then.

So let’s take a real example,

  • Get data from the database
  • Gets the items in the user’s shopping cart
  • Calculate the total price of goods

Assume that all the above operations are asynchronous and need to be executed sequentially

function getUser(userId) {
  return new Promise((resolve, reject) = > {
    console.log('Get user information from database');
    setTimeout(() = > {
      resolve({
        userId: userId,
        username: 'admin'
      });
    }, 1000); })}function getServiceCart(user) {
  return new Promise((resolve, reject) = > {
    console.log(` access${user.username}Shopping cart goods');
    setTimeout(() = > {
      resolve([
        {name: 'book'.price: 10},
        {name: 'phone'.price: 200}]); },3 * 1000);
  });
}

function getServiceCost(goods) {
  return new Promise((resolve, reject) = > {
    console.log(Calculate the total price of cart items:The ${JSON.stringify(goods)}. `);
    setTimeout(() = > {
      resolve(goods.reduce((total, cur) = > total + cur.price, 0));
    }, 2 * 1000);
  });
}

getUser(100)
  .then(getServiceCart)
  .then(getServiceCost)
  .then(console.log);

/ / output:
// Get user information from the database
// Get admin's shopping cart items
/ / calculation purchases goods total: [{" name ":" book ", "price" : 10}, {" name ":" phone ", "price" : 200}].
/ / 210
Copy the code

Promise solved the problem of callback hell, but it wasn’t elegant enough.

The async/await keyword has been introduced in ES2017, which allows you to write more concise code than promise and write it later.

Today we learned about the use of the promise chain to handle multiple asynchronous tasks.

Welcome to pay attention to my public number [xiaoshuai’s programming notes], follow me a little bit of progress every day