Home > Web Front-end > JS Tutorial > Detailed introduction to Async functions in ES6 (with examples)

Detailed introduction to Async functions in ES6 (with examples)

不言
Release: 2018-10-24 10:33:49
forward
2708 people have browsed it

This article brings you a detailed introduction to the Async function in ES6 (with examples). It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

async

The ES2017 standard introduces the async function, making asynchronous operations more convenient.

In terms of asynchronous processing, the async function is the syntactic sugar of the Generator function.

For example:

// 使用 generator
var fetch = require('node-fetch');
var co = require('co');

function* gen() {
    var r1 = yield fetch('https://api.github.com/users/github');
    var json1 = yield r1.json();
    console.log(json1.bio);
}

co(gen);
Copy after login

When you use async:

// 使用 async
var fetch = require('node-fetch');

var fetchData = async function () {
    var r1 = await fetch('https://api.github.com/users/github');
    var json1 = await r1.json();
    console.log(json1.bio);
};

fetchData();
Copy after login

In fact, the implementation principle of the async function is to wrap the Generator function and the automatic executor in a function inside.

async function fn(args) {
  // ...
}

// 等同于

function fn(args) {
  return spawn(function* () {
    // ...
  });
}
Copy after login

The spawn function refers to the automatic executor, such as co.

In addition, the async function returns a Promise object, you can also understand that the async function is a layer of encapsulation based on Promise and Generator.

async and Promise

Strictly speaking, async is a syntax and Promise is a built-in object. The two are not comparable, not to mention that the async function also returns a Promise object...

Here is mainly to show some scenarios. Using async will handle asynchronous processes more elegantly than using Promise.

1. The code is more concise

/**
 * 示例一
 */
function fetch() {
  return (
    fetchData()
    .then(() => {
      return "done"
    });
  )
}

async function fetch() {
  await fetchData()
  return "done"
};
Copy after login
/**
 * 示例二
 */
function fetch() {
  return fetchData()
  .then(data => {
    if (data.moreData) {
        return fetchAnotherData(data)
        .then(moreData => {
          return moreData
        })
    } else {
      return data
    }
  });
}

async function fetch() {
  const data = await fetchData()
  if (data.moreData) {
    const moreData = await fetchAnotherData(data);
    return moreData
  } else {
    return data
  }
};
Copy after login
/**
 * 示例三
 */
function fetch() {
  return (
    fetchData()
    .then(value1 => {
      return fetchMoreData(value1)
    })
    .then(value2 => {
      return fetchMoreData2(value2)
    })
  )
}

async function fetch() {
  const value1 = await fetchData()
  const value2 = await fetchMoreData(value1)
  return fetchMoreData2(value2)
};
Copy after login

2. Error handling

function fetch() {
  try {
    fetchData()
      .then(result => {
        const data = JSON.parse(result)
      })
      .catch((err) => {
        console.log(err)
      })
  } catch (err) {
    console.log(err)
  }
}
Copy after login

In this code, try/catch can capture some Promise construction errors in fetchData(), However, exceptions thrown by JSON.parse cannot be caught. If you want to handle exceptions thrown by JSON.parse, you need to add a catch function to repeat the exception handling logic.

In actual projects, error handling logic may be complex, which can lead to redundant code.

async function fetch() {
  try {
    const data = JSON.parse(await fetchData())
  } catch (err) {
    console.log(err)
  }
};
Copy after login

The emergence of async/await allows try/catch to capture synchronous and asynchronous errors.

3. Debugging

const fetchData = () => new Promise((resolve) => setTimeout(resolve, 1000, 1))
const fetchMoreData = (value) => new Promise((resolve) => setTimeout(resolve, 1000, value + 1))
const fetchMoreData2 = (value) => new Promise((resolve) => setTimeout(resolve, 1000, value + 2))

function fetch() {
  return (
    fetchData()
    .then((value1) => {
      console.log(value1)
      return fetchMoreData(value1)
    })
    .then(value2 => {
      return fetchMoreData2(value2)
    })
  )
}

const res = fetch();
console.log(res);
Copy after login

Detailed introduction to Async functions in ES6 (with examples)

Because the code in then is executed asynchronously, when you interrupt the point, the code It will not be executed sequentially, especially when you use step over, the then function will directly enter the next then function.

const fetchData = () => new Promise((resolve) => setTimeout(resolve, 1000, 1))
const fetchMoreData = () => new Promise((resolve) => setTimeout(resolve, 1000, 2))
const fetchMoreData2 = () => new Promise((resolve) => setTimeout(resolve, 1000, 3))

async function fetch() {
  const value1 = await fetchData()
  const value2 = await fetchMoreData(value1)
  return fetchMoreData2(value2)
};

const res = fetch();
console.log(res);
Copy after login

Detailed introduction to Async functions in ES6 (with examples)

When using async, you can debug it just like debugging synchronous code.

async hell

async hell mainly refers to the fact that developers are greedy for grammatical simplicity and turn content that can be executed in parallel into sequential execution, thus affecting performance, but using hell to describe it is a bit A bit exaggerated...

Example 1

For example:

(async () => {
  const getList = await getList();
  const getAnotherList = await getAnotherList();
})();
Copy after login

getList() and getAnotherList() actually have no dependency, but the current way of writing, Although simple, it causes getAnotherList() to be executed only after getList() returns, thus doubling the request time.

In order to solve this problem, we can change it to this:

(async () => {
  const listPromise = getList();
  const anotherListPromise = getAnotherList();
  await listPromise;
  await anotherListPromise;
})();
Copy after login

You can also use Promise.all():

(async () => {
  Promise.all([getList(), getAnotherList()]).then(...);
})();
Copy after login

Example 2

Of course the above This example is relatively simple, let's expand it again:

(async () => {
  const listPromise = await getList();
  const anotherListPromise = await getAnotherList();

  // do something

  await submit(listData);
  await submit(anotherListData);

})();
Copy after login

Because of the characteristics of await, the entire example has an obvious sequence. However, getList() and getAnotherList() actually have no dependencies. submit(listData) and submit( anotherListData) has no dependencies, so how should we rewrite this example?

Basically divided into three steps:

1. Find out the dependencies

Here, submit(listData) needs to be after getList() , submit(anotherListData) needs to be after anotherListPromise().

2. Wrap interdependent statements in async functions

async function handleList() {
  const listPromise = await getList();
  // ...
  await submit(listData);
}

async function handleAnotherList() {
  const anotherListPromise = await getAnotherList()
  // ...
  await submit(anotherListData)
}
Copy after login

3. Concurrently execute async functions

async function handleList() {
  const listPromise = await getList();
  // ...
  await submit(listData);
}

async function handleAnotherList() {
  const anotherListPromise = await getAnotherList()
  // ...
  await submit(anotherListData)
}

// 方法一
(async () => {
  const handleListPromise = handleList()
  const handleAnotherListPromise = handleAnotherList()
  await handleListPromise
  await handleAnotherListPromise
})()

// 方法二
(async () => {
  Promise.all([handleList(), handleAnotherList()]).then()
})()
Copy after login

Succession and concurrency

Question: Given a URL array, how to implement the succession and concurrency of the interface?

async Subsequent implementation:

// 继发一
async function loadData() {
  var res1 = await fetch(url1);
  var res2 = await fetch(url2);
  var res3 = await fetch(url3);
  return "whew all done";
}
Copy after login
// 继发二
async function loadData(urls) {
  for (const url of urls) {
    const response = await fetch(url);
    console.log(await response.text());
  }
}
Copy after login

async Concurrent implementation:

// 并发一
async function loadData() {
  var res = await Promise.all([fetch(url1), fetch(url2), fetch(url3)]);
  return "whew all done";
}
Copy after login
// 并发二
async function loadData(urls) {
  // 并发读取 url
  const textPromises = urls.map(async url => {
    const response = await fetch(url);
    return response.text();
  });

  // 按次序输出
  for (const textPromise of textPromises) {
    console.log(await textPromise);
  }
}
Copy after login

async error capture

Although we can use try catch to capture errors, But when we need to catch multiple errors and do different processing, try catch will soon lead to messy code, such as:

async function asyncTask(cb) {
    try {
       const user = await UserModel.findById(1);
       if(!user) return cb('No user found');
    } catch(e) {
        return cb('Unexpected error occurred');
    }

    try {
       const savedTask = await TaskModel({userId: user.id, name: 'Demo Task'});
    } catch(e) {
        return cb('Error occurred while saving task');
    }

    if(user.notificationsEnabled) {
        try {
            await NotificationService.sendNotification(user.id, 'Task Created');
        } catch(e) {
            return cb('Error while sending notification');
        }
    }

    if(savedTask.assignedUser.id !== user.id) {
        try {
            await NotificationService.sendNotification(savedTask.assignedUser.id, 'Task was created for you');
        } catch(e) {
            return cb('Error while sending notification');
        }
    }

    cb(null, savedTask);
}
Copy after login

In order to simplify the capture of this kind of error, we can give promise after await Object adds a catch function, for which we need to write a helper:

// to.js
export default function to(promise) {
   return promise.then(data => {
      return [null, data];
   })
   .catch(err => [err]);
}
Copy after login

The entire error catching code can be simplified to:

import to from './to.js';

async function asyncTask() {
     let err, user, savedTask;

     [err, user] = await to(UserModel.findById(1));
     if(!user) throw new CustomerError('No user found');

     [err, savedTask] = await to(TaskModel({userId: user.id, name: 'Demo Task'}));
     if(err) throw new CustomError('Error occurred while saving task');

    if(user.notificationsEnabled) {
       const [err] = await to(NotificationService.sendNotification(user.id, 'Task Created'));
       if (err) console.error('Just log the error and continue flow');
    }
}
Copy after login

Some discussions on async

async will replace Generator ?

Generator is originally used as a generator. Using Generator to handle asynchronous requests is just a hack. In terms of asynchronousness, async can replace Generator, but the two syntaxes of async and Generator are used to solve different problems. of.

Will async replace Promise?

  1. The async function returns a Promise object

  2. In the face of complex asynchronous processes, the all and race provided by Promise will be more useful

  3. Promise itself is an object, so it can be passed arbitrarily in the code.

  4. The support rate of async is still very low. Even with Babel, it needs to be compiled after compilation. Add about 1000 lines.


The above is the detailed content of Detailed introduction to Async functions in ES6 (with examples). For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:segmentfault.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template