To eliminate asynchronous callbacks, it has to be async-await

This article has participated in the "Newcomer Creation Ceremony" event to start the road of gold creation together.

In this article, I will take you to understand the romance between async~await.

Regarding asynchronous processing, ES5's callback made us fall into the cycle of callback hell. Later, ES6's Promise ( Promise does not understand? Click here to understand ) let us get out of the cycle. Finally, ES7's async-await brings us to the light. Today we will learn about async-await for a summer and see how it is related and different from Promise.

1. Walk into the principle of Async-await
1. Principle 1

async函数返回一个 Promise 对象,可以使用then方法添加回调函数. for example:

// async返回的是Promise对象?
async function testAsync() {
    return 'hello';//上篇文章Promise对象的返回值如果不是Promise,会通过Promise.resolve()转化为Promise,再进行处理
}
const result = testAsync()
console.log(result);//Promise { 'hello' }  说明async返回的是Promise对象

So since async returns a Promise object, then the function behind async can be connected to .then() or .catch()...? We'll find out when we try it.

// async返回的是Promise对象,并且可以接Promise的方法?
async function testAsync() {
    // await await等待还是promise对象
    return 'hello'
}
testAsync()
    .then((result)=>{
        console.log(result);
    })
    .catch((error)=>{
        console.log(error);
    })
//hello  妈耶!打印了!说明async返回的是Promise对象,并且可以接Promise的方法,并且!!!默认状态是resolved的

The above code shows,async函数内部return语句返回的值,会成为then方法回调函数的参数

2. Principle 2

当async函数内部抛出错误的时候,会导致返回的 Promise 对象变为reject状态. The thrown error object will be received by the second callback function of the .then() method or the callback function of the .catch() method.

// async函数内部抛出错误或者Promise状态为reject
async function testError(){
    //throw new Error('出错啦~~');
    await Promise.reject('出错了');//await前面有return和没有return效果一样
} 
testError()
    // .then(()=>{},(error)=>{console.log(error);})
    .catch(error=>{console.log(error);})
//Error: 出错啦~~
3. Principle 3

await命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值. Code description:

// await
async function getName(){
    // return '来自星星的你';
    return await '来自星星的你';//上面直接return等价于这个return
}
getName()
    .then(result=>{console.log(result);})
//来自星星的你
4. Principle 4

await的使用,必须要有async. This is the romance of async-await: async returns a Promise object, and await waits for this Promise object, so await cannot be without async (but async can be without await). Have you been romanticized? I'm drunk anyway. What if await doesn't have async? Error:

// await没有async会报错
function testAwait(){
    return await '西红柿炒辣椒'
}
testAwait()
    .catch(error=>{
        console.log(error);
    })
//SyntaxError: await is only valid in async function
2. In-depth Async-await rules
1. async encapsulates Promise
// async封装Promise
async function fn1() {
    return '喜羊羊与灰太狼';// //相当于return Promise.resolve('喜羊羊与灰太狼')
    const data = await fn1();//接收data值
}
fn1()//执行async函数,返回的是一个Promise对象
    .then(data => {
        console.log('content =', data)
    })
​
//content = 喜羊羊与灰太狼
2. await is equivalent to then
// await---.then()
async function getName(){
    const operate=Promise.resolve('白雪公主')//执行函数
    const name= await operate //await相当于Promise的then  operate.then(name=>{})
    console.log('name:',name)
}
getName();
( async function(){
    const person=await '七个小矮人' //await Promise.resolve('七个小矮人') await后面不跟Promise,也会被封装成Promise
    console.log('person:',person)//400
})();//自执行函数
​
//name: 白雪公主
//person: 七个小矮人
3. When multiple awaits are executed, they are executed in sequence

When the function is executed, once it encounters await, it will return first, wait until the asynchronous operation is completed, and then execute the following statements in the function body. 任何一个await语句后面的 Promise 对象变为reject状态,那么整个async函数都会中断执行.

async function testOrder() {
    await Promise.reject('出错了')//UnhandledPromiseRejectionWarning: 出错了
    await Promise.resolve('hello world'); // 不会执行
}
testOrder();
4. try...catch is equivalent to catch

If you want to not interrupt subsequent async operations even if the previous one fails. Yes 将第一个await放在try...catch结构里面, so that the second await will be executed regardless of whether the asynchronous operation is successful or not.

// try...catch
!(async function () {
    const testError = Promise.reject('出错啦~~~')//rejected状态
    // const testError=throw new Error('出错啦~~~');
    try {
        const result = await testError; //await相当于then,但是reject不会触发then
        console.log('success:'+result) //不会输出,因为const result = await testError被报错,被catch捕获
    } catch (error) {
        console.error('error:'+error)//try...catch 相当于Promise的catch
    }
​
})()
//error:出错啦~~~

When await is followed by a Promise object, we get the 也可直接在await后面直接.catch捕获error:

async function testError() {
    await Promise.reject('出错了')
        .catch(error => console.log(error));//这里捕获错误,不会影响下一个await执行
    
    return await Promise.resolve('hello world');
}
​
testError()
    .then(result => console.log(result))
3. Parse Async-await syntax

Let's take a look at an interview question:

// 面试题
function getJSON() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log(2);
            resolve(2)
        }, 2000)
    })
}
async function testAsync() {
    await getJSON()
    console.log(3);
}
testAsync()
//2
//3

问题当然不会问打印顺序啦,问题是将async await语句解析翻译为Promise?

根据现在的知识面,我们必须知道:

(1)await不能单独出现,其函数前面一定要有async。

(2)await会干两件事:

第一,将写在await后面的代码放到async创建的那个Promise里面执行。

第二、将写在await下面的代码放到前一个创建的那个Promise对象的.then里面执行。

(3)await返回的也是Promise对象,他只是把await下面的代码放到了await返回的promise的.then里面执行。

这样的话,是不是如鱼得水了。翻译如下:

function getJSON() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log(2);
            resolve(2)
        }, 2000)
    })
}
// 编译成Promise原理
function testAsync() {
    return Promise.resolve().then(() => {
        return getJSON();
    })
        .then(() => {
            console.log(3);
​
        })
}
testAsync()
四、拓展Async-await应用
1、场景1

你学废async-await了嘛?还记得上一篇开篇的回调地狱嘛?我们通过Promise解决回调是这样的:

// Promise解决方式
function doCallback(n) {
    var myPromise = new Promise(function (resolve, reject) {   
        //处理异步任务
        var flag = true;
        setTimeout(function () {
            if (flag) {
                resolve(n)
            }
            else {
                reject('失败')
            }
        },0)
    })
    return myPromise;
}
​
doCallback(1)
    .then((result) => { //then是成功执行的方法 返回的还是一个Promise对象
        console.log(result);//打印张三  res是执行
        return fn(2);
    })
    .then((result) => {
        console.log(result);
        return fn(3)
    })
    .then((result) => {
        console.log(result);
        return fn(4)
    })
    .then((result) => {
        console.log(result);
    })
    .catch((result) => { //catch是失败执行的方法
        console.log(result);
    })
    //好多.then,形成.then链啦
//1
//2
//3
//4

通过以上Promise方法,可以明显解决回调地狱“向右移”的浮夸表现,但是,Promise是基于 then, catch 的链式调用,但也是基于回调函数。.then链多多少少还是违背原生代码,显得也不是很优雅。作为回调终极武器,async-await更加贴近于原生代码,我们看一下吧:

//封装一个返回promise的异步任务
function doCallback(str) {
    var myPromise = new Promise(function (resolve, reject) {
        var flag = true;
        setTimeout(function () {
            if (flag) {
                resolve(str)
            } else {
                reject('处理失败')
            }
        })
    })
    return myPromise;
}
​
//封装一个执行上述异步任务的async函数
async function testAsync() {
    var result1 = await doCallback(1);  //await直接拿到fn()返回的promise的数据,并且赋值给result
    var result2 = await doCallback(2);  //await 后面的代码,都可以看做是异步回调 callback 里的内容,都是异步的
    var result3 = await doCallback(3);
    var result4 = await doCallback(4);
    console.log(result1);
    console.log(result2);
    console.log(result3);
    console.log(result4);
}//这样是不是简洁优雅多了呢?
//执行函数
testAsync();
//1
//2
//3
//4

有了 async-await、promise 还有必要学习吗?通过上面async-await的解决方案可以瞧见,async / await 和 Promise 并不互斥,二者相辅相成。同时async / await 并不能改变异步的本质( js是单线程的,异步需要回调,都是要基于 event loop 来实现(什么是event loop?关注我,等我文章~))。

总结

现在知道了,async-await是promise的语法糖了吧,不仅让我们书写代码时更加流畅,而且增强了代码的可读性。特别注意的是:虽然async-await 是建立在 Promise机制之上的,但是并不能取代其地位,他们两者相辅相成,息息相关。其实async-await不止是Promise的语法糖,还是Generator的语法糖,Generator是什么?我们下篇见分晓。

heiehi.webp

Guess you like

Origin juejin.im/post/7122478595787718663