也许看到这些单词你第一反应就是“异步”,但你是否真的能好好使用它呢?
早在以前,我们都是通过回调的方式解决异步操作问题,就是运行一个函数,将另一个函数作为参数传进要执行的函数里,如下:
1 2 3 4 5 6 7 8 9 | function f1(callback) { setTimeout(function () { callback(); }, 2000); } var f2 = function(){ console.log('回调') } f1(f2) |
采用这种方式,我们把同步操作变成了异步操作,f1不会堵塞程序运行,相当于先执行程序的主要逻辑,将耗时的操作推迟执行。
回调函数是异步编程最基本的方法,其优点是简单、容易理解和部署,缺点是不利于代码的阅读和维护,各个部分之间高度耦合(Coupling),流程会很混乱,而且每个任务只能指定一个回调函数。
Promise最大的好处是在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了,你可以在需要的时候自主的给出成功或失败,而返回的依然是一个promise对象,你可以继续通过then方式嵌套,then方法里面接收一个函数,函数的参数就是上个promise的return返回结果如下:
1 2 3 4 5 6 7 8 9 10 | var p1 = new Promise(function (resolve, reject) { setTimeout(resolve, 500); }); var p2 = new Promise(function (resolve, reject) { setTimeout(resolve, 600, 'P2'); }); // 同时执行p1和p2,并在它们都完成后执行then: Promise.all([p1, p2]).then(function (results) { console.log(results); // 获得一个Array: [undefined, 'P2'] }); |
async 函数算是一个语法糖,使异步函数、回调函数在语法上看上去更像同步函数。Async和promise息息相关,其实它的核心还是promise,不同的是Async解决了promise的层层嵌套问题,并且很好的阻断了当代码发生异常时候阻断代码执行,async 返回一个Promise,因此这个函数可以通过then添加回调函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | function timeout(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); // 一定要执行resolve,否则await后面函数不往下执行 }); } function timeout1(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); }); } async function fn() { await timeout(1000); console.log(111) await timeout1(3000);//等待timeout函数执行完毕 console.log(123321)//等待timeout1执行完毕 return await('执行了!'); } /*注:当一个 async 函数中有多个await时,这些 await是继发执行的, 只有当前一个await后面的方法执行完毕后,才会执行下一个*/ fn().then(res => { console.log(res) }).catch((err) => { console.log(err) }) |
可以看到,在 async 函数中,出现了一个陌生的关键字await——这个关键字只能够在 async 函数中使用,否则将会报错,它的意思是紧跟在其后面的表达式需要被等待执行结果,同时值得注意的是,你必须将await等待的结果通过return出去,在fn().then里才能去接收到结果,否则会是undefined,这个同promise是一致的。
await命令后面可以是Promise也可以是普通数据类型,但如果是普通数据类型的话,会自动转换成状态为resolve的Promise,如果await后面的Promise状态转变成了reject,那么整个 async 函数都会停止执行,并且抛出相应的错误。即使这里没有return,也一样可以传入错误回调的参数,所以当一个 async 函数中有多个 await命令时,如果不想因为一个出错而导致其与的都无法执行,应将await放在try...catch语句中执行。
1 2 3 4 5 6 7 8 9 | (async function testAwait () { try { //监听下面方法有可能会抛出错误 await func1() await func2() await func3() } catch (error) { console.log(error) } })() |
上述说到,当一个 async 函数中有多个await时,这些 await是继发执行的,只有当前一个await后面的方法执行完毕后,才会执行下一个,如果我们前后的方法由依赖关系,继发执行是没有问题的,但是如果并没有任何关系的话,这样就会很耗时,所以需要让这些await命令同时执行,也就是并发执行。
1 2 3 4 5 6 7 8 | // 方法 1 let [res1, res2] = await Promise.all([func1(), func2()]) // 方法 2 let func1Promise = func1() let func2Promise = func2() let res1 = await func1Promise let res2 = await func2Promise |
支付宝扫一扫打赏
微信扫一扫打赏
共 0 条评论关于"你是否有了解Promise、Async and await"
最新评论