ES7 async/await

ES7引入的async/await在JavaScript异步编程中是一个很好的改进,它提供了使用同步样式的代码异步访问resources资源的方式,而且不会阻塞线程。

  • async/await用于编写JavaScript异步程序
  • async/await代码书写方式和同步编程相似,代码简洁易读。
  • async/await基于Promise
  • async/await中可使用try-catch捕获异常

async

  • async函数

async函数返回的是一个Promise对象,async函数包括函数语句、函数表达式、Lambda表达式。

async函数会返回一个Promise对象,如果在async函数中return一个直接量,async会将这个直接量通过Promise.resolve()封装成Promise对象。

async function fn(){
    return 1;
}
console.log(fn());//Promise {<resolved>: 1}
4933701-71eae9a31fe951fd.png
image.png

async函数调用时会返回Promise对象,Promise对象拥有status和value。如果async函数拥有返回值,当调用async函数时,函数内部会调用Promise.resolve()方法将其转化为一个Promise对象并作为返回。

如果async函数没有返回值,则会返回Promise.resolve(undefined)。

async function fn(){
}
console.log(fn());//Promise {<resolved>: undefined}
4933701-ef1c141aba476de3.png
image.png

async函数调用时函数内部如果抛出错误则出现错误

async function fn(){
    throw new Error("rejected");
}
console.log(fn());
4933701-fdd0b58bdee68ad0.png
image.png
  • async关键放在函数前,async关键字后意味着函数将返回一个Promise。

在函数前添加async关键字后意味着函数将返回一个Promise,JavaScript编译器会自动函数返回值转换为一个Promise。

async function fn(){
  return 1;
}
fn().then(alert);//1
function fn(){
    return Promise.resolve(1);
}
fn().then(alert);//1
fn().then(console.log);//1

如果要获取async函数的执行结果,需要调用Promise对象的then或catch来为其注册回调函数。

async function fn(){
    return 1;
}
fn().then(result=>console.log(result));//1

如果async函数执行完毕返回的Promise对象没有注册回调函数,比如函数内部做了一次for循环此时函数的调用就只是执行了函数体,这和普通的函数并没有区别。唯一的不同之处在于函数体执行完毕后返回的是一个Promise对象。

async function fn(){
    for(let i=0; i<10; i++){
        console.log("async fn:", i);
    }
}
console.log(fn());
4933701-dcb337f1eefdada4.png
image.png

async函数的执行会返回一个Promise对象,并将内部的值进行promise封装,如果Promise对象通过then或catch方法注册了回调函数,async函数执行完毕后,注册的回调函数会放入到异步队列中等待执行。如果只是async函数则和promise一样,但有了await之后就不一样的,await关键字只能放到async函数中,await等待的是什么呢?

await

await等待的是一个表达式,这个表达式的计算结果是Promise对象或其他值,换句话说await可以等待任意表达式的结果。如果await等到的不是一个Promise对象,那么await表达式的运算结果就是它等到的东西。如果await等到的是一个Promise对象,await就会阻塞后续代码,等到Promise对象resolve,然后得到resolve的值作为await表达式的运算结果。

这也就是await必须用在async函数中的原因,async函数调用不会造成阻塞,async函数内部所有的阻塞都被封装在一个Promise对象中异步执行。

let result = await promise;
  • await关键字的含义是让JavaScript编译器等待Promise并返回结果

await的意思是让JavaScript编译器等待Promise结束,然后再输出结果。这里并不会占用CPU资源,因为JavaScript引擎可以同时执行其它任务或脚本或处理事件。

async function fn(){
    
    let promise = new Promise((resolve, reject)=>{
        setTimeout(()=>resolve("done"), 1000);
    });
    let result = await promise;//wait till the promise resolve
    console.log(result);//done
}
fn();

fn函数执行时会在let result = await promise位置暂停,直到Promise返回结果,因此代码会在1秒后在控制台输出done。

  • await只能在async中运行

await不能单独使用,必须在async函数的作用域下使用,否则将会报异常Error:await is only valid in async function

function fn(){
    let promise = new Promise((resolve, reject)=>{
        setTimeout(()=>resolve("done"), 1000);
    });
    let result = await promise;//Uncaught SyntaxError: await is only valid in async function
    console.log(result);
}
fn();

例如:摇色子等待3秒后得到最终的结果

function fn(){
    let val = parseInt(Math.random() * 6 + 1);
    let promise = new Promise((resolve, reject)=>{
        setTimeout(()=>resolve(val), 3000);
    });
    return promise;
}
async function main(){
    let val = await fn();
    console.log(val);
}
main();

例如:摇色子猜大猜小,成功与失败的处理。

function fn(type){
    return new Promise((resolve, reject)=>{
        let val = parseInt(Math.random() * 6 + 1);
        if(val > 3){
            if(type === "big"){
                resolve(val);
            }else{
                reject(val);
            }
        }else{
            if(type === "big"){
                reject(val);
            }else{
                resolve(val);
            }
        }
        setTimeout(()=>resolve(val), 3000);
    });
}
async function main(){
    try{
        let val = await fn("big");
        console.log("win:", val);
    }catch(error){
        console.error("fail:", error);
    }
}
main();

例如:有两个色子都买大,猜成功则返回两个的值,猜失败则返回第一个失败的结果。

function fn(type){
    return new Promise((resolve, reject)=>{
        let val = parseInt(Math.random() * 6 + 1);
        if(val > 3){
            if(type === "big"){
                resolve(val);
            }else{
                reject(val);
            }
        }else{
            if(type === "big"){
                reject(val);
            }else{
                resolve(val);
            }
        }
        setTimeout(()=>resolve(val), 3000);
    });
}
Promise.all([fn("big"), fn("big")]).then(
    (val)=>console.log("resolve:", val), 
    (val)=>console.log("reject:",val)
);

例如:话费充值,当用户输入电话号码后先查找电话号码所在的省市,在根据省市找到可能的重置面额。

4933701-f3f0f15622482583.png
charge

创建项目安装依赖

$ mkdir charge && cd charge
$ npm init
$ npm i --save express
$ npm i --save body-parse
$ npm i -g supervisor

创建服务器

$ vim index.js
const express = require("express");
const bodyParser = require("body-parser");
const app = express();

app.use(express.static("public"));
app.use(bodyParser.json());

app.post("/location", (req, res, next)=>{
    const phone = req.body.phone;
    setTimeout(()=>{
        res.json({error:false, code:200, message:"success", result:{province:"湖南", city:"长沙"}});
    }, 1000);
});
app.post("/facelist", (req, res, next)=>{
    const province = req.body.province;
    const city = req.body.city;
    setTimeout(()=>{
        res.json({error:false, code:200, message:"success", result:["20元", "30元", "50元"]});
    }, 1000);
});

app.listen(3000, ()=>console.log("server start"));

创建视图界面

$ vim /public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link href="https://cdn.bootcss.com/twitter-bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet">
    <title>Document</title>
</head>
<body>
    <div id="app" class="container">
        <h3 class="text-center">手机话费充值</h3>
        <hr>
        <div class="form-group">
            <div class="input-group">
                <div class="input-group-prepend">
                    <label class="input-group-text">电话号码</label>
                </div>
                <input type="text" class="form-control" v-model="phone">
                <span class="input-group-append">
                    <button class="btn btn-primary" @click="getItems">确定</button>
                </span>
            </div>
        </div>
        <hr>
        <div id="result">
            <div class="form-group" v-show="show">
                <div class="input-group">
                    <div class="input-group-prepend">
                        <div class="input-group-text">所属地区</div>
                    </div>
                    <input type="text" class="form-control" v-model="province"/>
                    <input type="text" class="form-control" v-model="city"/>
                </div>
            </div>
            <div class="form-group" v-for="item in items" :key="item">
                <div class="input-group">
                    <div class="input-group-prepend">
                        <div class="input-group-text">
                            <input type="radio">
                        </div>
                    </div>
                    <input type="text" class="form-control" :value="item">
                </div>
            </div>
        </div>
    </div>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
<script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
<script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.min.js"></script>
<script>
    const el = "#app";

    let data = {};
    data.phone = "";
    data.province = "";
    data.show = false;
    data.city = "";
    data.items = [];

    const vm = new Vue({
        el:el,
        data:data,
        methods:{
            getItems(){
                console.log(this.phone);
                this.getLocation(this.phone).then(res=>{
                    if(res.status === 200 && res.data.error===false){
                        const province = res.data.result.province;
                        const city = res.data.result.city;

                        this.show = true;
                        this.province = province;
                        this.city = city;

                        this.getFacelist(province, city).then(res=>{
                            if(res.status===200 && res.data.error===false){
                                this.items = res.data.result;
                            }
                        }).catch(err=>console.error(err));
                    }else{
                        console.error(res.data.message);
                    }
                }).catch(err=>console.error(err));
            },
            getLocation(phone){
                return axios.post("/location", {phone});
            },
            getFacelist(province, city){
                return axios.post("/facelist", {province, city});
            }
        }
    });
</script>
</body>
</html>

访问页面 http://127.0.0.1:3000

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值