javaScript异步编程解决方案的变迁

异步解决方案的变迁

callback

在JavaScript的世界中,所有代码都是单线程执行的。所以JavaScript的所有网络操作、浏览器事件,都必须是异步执行(虽然Ajax请求可以同步,但因为会阻塞主线程,造成页面卡顿,不推荐使用

回调函数(callback)是一段可执行的代码段,它以参数的形式传递给其它代码,在其合适的时间执行这段回调函数的代码。它的执行本身是同步的,但因为注册时间与执行时机的解耦,整个过程看起来就是异步的了。
优点:相比于同步,不会阻塞主线程,提高整体代码运行效率。
缺点:回调地狱,代码可读性、可维护性差,剥夺了回调函数返回结果的能力

链式调用

为解决回调地狱的问题,开发者想出以链式调用的方式来组装代码逻辑,这样把执行代码和处理代码分离开,使异步操作逻辑更加清晰。

jQuery.Deferred

首先,回顾一下jQuery的ajax操作的传统写法:

$.ajax({
  url: "test.html",
  success: function () {
    alert("哈哈,成功了!");
  },
  error: function () {
    alert("出错啦!");
  },
});

$.ajax()操作完成后,如果使用的是低于1.5.0版本的jQuery,返回的是XHR对象,你没法进行链式操作;如果高于1.5.0版本,返回的是deferred对象,可以进行链式操作。
以上例子就可以改写为:

$.ajax('test.html')
 .then(function () {
   alert("哈哈,成功了!");
 })
 .fail(function () {
   alert("出错啦!");
 });

有点:从上面可以看出来,它的写法与现代的Promise比较类似了。比thenjs看起来优雅些,不需要在then中手动触发到下一步。
缺点:链接处理内部错误捕捉不足。

Promise

终极异步解决方案,借鉴了jQuery.Deferred的设计,算是链式调用的最佳方案。

doSomething()
.then(result => doSomethingElse(result))
.then(newResult => doThirdThing(newResult))
.then(finalResult => {
  console.log(`Got the final result: ${finalResult}`);
})
.catch(failureCallback);

优点:相较于jQuery,更好地进行错误捕获。
缺点:就是链式调用的通用缺点。
1.无法取消。
2.性能损耗。每个Promise都是new了一个新的对象,每个then、catch又返回一个新的Promise,这些都是损耗。而且延时肯定永远不可能比直接执行callback快。
3.内错难抛。有些内部错误无法抛出,比如状态已经变化后再发生的错误。
4.堆栈复杂。当处于 Pending 状态时,无法得知目前进展到哪一个阶段。我们调试代码时也会发现堆栈变得相当复杂。
5.不够优雅。对于追求完美的我们而言,then写多了,看起来仍不够优雅。

generator

有人这样说:

异步编程的语法目标,就是怎样让它更像同步编程。

确实是大实话。于是,generator应运而生。
generator是生成器的意思,熟悉Python的同学应该会了解,被称为协程的关键实现,ES6的generator设计其实就是借鉴的Python。
它需要使用yield关键字,代码如下:

function* foo(x) {
    yield x + 1;
    yield x + 2;
    return x + 3;
}
const f = foo(0);
console.log(f.next()); // { value: 1, done: false }
console.log(f.next()); // { value: 2, done: false }
console.log(f.next()); // { value: 3, done: true }

async/await

async/await的出现,算是终极大招。在可见的未来里,应该找不到更优秀的方案了。目前,像C#、Python、Rust、Dart等语言都已经支持这俩关键字。

function getSomething() {
    return "something";
}

async function testAsync() {
    return "hello async";
}

async function testAsync2() {
    return Promise.resolve("hello async2");
}

async function test() {
  try {
    const v1 = await getSomething();
    const v2 = await testAsync();
    const v3 = await testAsync2();
    console.log(v1, v2, v3);
  } catch(e) {
    console.error(e);
  }
}

test();

加了async的函数,返回类型就是一个Promise,即使原来不是Promise。其实相当于执行了Promise.resolve()方法。
而await关键字可以等待异步函数,也支持同步的函数。
使用try/catch也可以进行异常或错误的捕获,算是比较完美了。

当然,它只是Promise的语法糖,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值