详解 JavaScript 3种异步方式(Promise/async/Generator)

前言

JavaScript 是一个单线程语言,但是也不乏一些异步操作,比如定时器,浏览器事件,回调等。还有耳熟能详的 Promise。自从 ES6 出来之后,提供了更丰富的异步方式。比如 async 函数,Generator 函数。今天就给大家分享一下这3种异步的用法以及区别。

在开始讲解这三个异步函数用法之前,我们通过一个案例来体会一下什么叫异步和同步。

1. 异步

 setTimeout(function (res) {
        console.log(res)
    },3000,"我是3秒钟之后打印")
    setTimeout(function (res) {
        console.log(res)
    },2000,"我是2秒钟之后打印")
    setTimeout(function (res) {
        console.log(res)
    },1000,"我是1秒钟之后打印")

打印结果为:
在这里插入图片描述
众所周知,setTimeout 是异步函数,异步函数的特点之一就是什么时候到点了,就什么时候执行。这跟 Promise 的命名异曲同工,Promise 是承诺的意思。即承诺什么时候执行,就什么时候执行。所以以上的打印顺序根据计时器的时间判定应该是"我是1秒钟之后打印"、“我是2秒钟之后打印”、“我是3秒钟之后打印”。

2. 同步(使用回调将异步变同步)
那么问题来了。如果想让以上的异步执行顺序变成同步的昵? 即打印顺序为 “我是3秒钟之后打印”、“我是2秒钟之后打印”、“我是1秒钟之后打印”。
在 Promise 、async 和 Generator 函数没有出来之前,我们的做法就是使用回调函数。

    function beSync() {
        setTimeout(function (res) {
            console.log(res);
            setTimeout(function (res) {
                console.log(res);
                setTimeout(function (res) {
                    console.log(res)
                },1000,"我是1秒钟之后打印")
            },2000,"我是2秒钟之后打印")
        },3000,"我是3秒钟之后打印")
    }
    beSync();
   

打印结果为:
在这里插入图片描述

3. 分析回调
通过回调实现了将异步变成同步。以上代码有以下几个问题。

  1. 回调里面层层嵌套,代码冗余;
  2. 回调太多,不免有些分辨不出,那个参数来源于那个函数的回调;
  3. 代码之间耦合度太高,一旦有一个回调出现错误,其他回调都会遭殃;
  4. 不能用 try catch 来捕获错误。

基于以上的问题分析,异步解决方案 Promise 函数、async 函数及Generator 函数应运而生。我们来学习一下这3个函数,并使用这3个函数解决以上问题。

一、Promise 函数

  1. 用法
var promise = new Promise(function(reslove,reject){
if(){
	//异步函数成功
	reslove(res)// res是异步函数成功的所获取的参数
	}else{
	//异步函数失败
	reject(err)
	}
})
  1. 示例
var promise = new Promise(function(reslove,reject){
	setTimeout(function(res){
	    reslove(res)
	},1000,'成功')
	});
promise.then(function(res){
 	 console.log(res);//'成功'
})
  1. 解决以上案例
    var promise = new Promise(function (resolve) {
        setTimeout(function (res) {
            resolve(res)
        },3000,"我是3秒钟之后打印")
    })
    promise
        .then(function (res) {
        console.log(res);//"我是3秒钟之后打印"
        return new Promise(function (resolve) {
            setTimeout(function (res) {
                resolve(res)
            },2000,"我是2秒钟之后打印")
        })
    })
        .then(function (res) {
         console.log(res);//"我是2秒钟之后打印"
         return new Promise(function (resolve) {
         setTimeout(function (res) {
            resolve(res)
        },1000,"我是1秒钟之后打印")
    })
        .then(function (res) {
            console.log(res);//"我是1秒钟之后打印"
    })
})

打印结果为:
在这里插入图片描述
Promise 优点是代码结构看上去很清晰,每一个 then 里面的参数都是上一个异步返回的结果对象。缺点是所有的回调都放在 then 里面,没有语义性。

二、Generator 函数

  1. 用法
    Generator 函数有两个明显特征,一是 function 与函数名之间有*号,二是在函数内部使用 yield 表达式,定义不同的内部状态。yield 表示中止执行,而 next 方法表示开启执行,返回的状态值为 yield 后面的表达式结果。
    Generator 函数返回一个遍历器对象。

  2. 示例

function * hello() {
    yield '1';
    yield '2';
    return 'end'
}
var text = hello();
console.log(text.next());
console.log(text.next());
console.log(text.next());

打印结果为:
在这里插入图片描述

  1. 解决以上案例
   function* helloWorld() {
        yield new Promise((resolved)=>{
            setTimeout(function (res) {
                resolved('我是3秒钟之后打印');
            }, 3000);
        });
        yield new Promise((resolved)=>{
            setTimeout(function (res) {
                resolved('我是2秒钟之后打印');
            }, 2000);
        });
        yield new Promise((resolved)=>{
            setTimeout(function (res) {
                resolved('我是1秒钟之后打印');
            }, 1000);
        });
    };
    var hw = helloWorld();
    hw.next().value
        .then(function (res) {
            console.log(res);
    })
        .then(function () {
        hw.next().value.then(function (res) {
            console.log(res);
        })
        .then(function () {
        hw.next().value.then(function (res) {
            console.log(res);
         });
        })
    })

在这里插入图片描述

三、async 函数

  1. 用法
    async 函数 是 Generator 函数的语法糖,它只是将 Generator 函数中的 * 变成了async ,yield 变成了 await,更具有语义性。
    async 函数直接执行,不需要通过 next。
    async 函数返回的是一个 promise 对象,可以使用 then 方法添加回调函数。

  2. 示例

  async function func() {
        return 'hello';
    }
    func().then(function (res) {
        console.log(res)//'hello'
    })
  1. 解决以上案例
    async function helloWorld() {
        await new Promise(function (resolve) {
            setTimeout(function (res) {
                console.log(res);
                resolve(res)
            }, 3000, '我是3秒钟之后打印');
            });
        await new Promise(function (resolve) {
            setTimeout(function (res) {
                console.log(res);
                resolve(res)
            }, 2000, '我是2秒钟之后打印');
        });
        await new Promise(function (resolve) {
            setTimeout(function (res) {
                console.log(res);
                resolve(res)
            }, 1000, '我是1秒钟之后打印');
        });
    };
    helloWorld()

打印结果为:
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值