简析JavaScript异步编程

什么是同步?

要了解什么是异步,首先应该知道同步这个概念

因为JavaScript是单线程的,所谓单线程就是一次只能执行一件任务,只有当前面的任务执行完毕后才会继续执行后续任务,程序的执行顺序和任务的排列顺序是一致的。

同步JavaScript优缺点:

  1. 优点

实现简单,执行环境单纯,不需要共享资源(不需要锁机制 ),以主线程执行结果为准·

  1. 缺点

如果一个任务行执行时间较长,后面的任务会被阻塞,影响整个程序的执行

什么是异步?

虽然JavaScript是单线程的,但是其执行的任务被分为同步任务和异步任务两种。

同步任务:

在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;

异步任务:

不进入主线程,而进入"任务队列"(task queue),只有等主线程任务执行完毕,"任务队列"开始通知主线程,请求执行任务,该任务才会进入主线程执行。

这种不断检查然后从任务队列中取出对应的事件放入函数的调用栈中执行被称作事件循环

关于任务队列相关知识看这里 一篇文章快速搞懂JavaScript事件循环、任务队列、同步异步和阻塞非阻塞

为什么要有异步?

有这种异步任务的设计是因为要想从服务器获取某个资源是需要一定的时间的,进行IO操作时,cpu比较空闲,那么完全可以让cpu挂起正在执行的任务,先运行后续的任务,等到IO操作返回结果了,再把挂起的任务执行完毕。

异步带来的问题

因为异步任务会在同步任务全部执行完毕才去执行,假如后面的代码依赖前面返回的内容,这时候就会出错

比如说下面代码想实现发送ajax请求后,控制台输出服务端返回的结果,结果输出undefined

function res (){
    // get请求
    var xhr = new XMLHttpRequest();
    xhr.open('GET', 'http://localhost:5000/jsonp/', true);
    // xhr.withCredentials = true
    xhr.send();
    xhr.onreadystatechange = function (e) {
        if (xhr.readyState == 4 && xhr.status == 200) {
            return xhr.responseText
        }
    };
}
console.log(res())  //undefined

因为ajax请求为异步任务,会被放进任务队列中,等待同步任务(console.log(res()))执行完毕再执行,所以console.log(res())时打印undefined


所以JavaScript中指的异步编程实际上是指将异步执行的代码,变为同步执行(等待某部分代码执行完毕,再执行另一部分代码)

callback回调函数

最基本的实现异步编程的方法就是callback回调函数,异步callbacks 其实就是正常的函数,只不过是作为参数传递给那些在后台执行的其他函数,当那些后台运行的代码结束,就调用callbacks函数

最常见的callback回调就是事件监听了,为按钮绑定点击事件

btn.addEventListener('click', () => {
  alert('You clicked me!');
});

事件监听的第一个参数是事件类型,第二个就是回调函数。这里将回调函数作为事件监听addEventListener函数的参数,所以回调函数不会立即执行,事件监听会负责在合适的时候执行回调函数

当然也可以自己写一个包含callback的函数createCallback

// 回调1
function callbackOne (){
	console.log('我是回调1')
}
// 回调2
function callbackTwo (){
	console.log('我是回调2')
}

creatCallback(doSomething,callbackOne,callbackTwo)


回调函数优点

简单,容易实现

回调函数缺点
不利于代码阅读和维护,各部分之间高度耦合,而且每个任务只能设置一个回调函数,当有多个请求相互依赖的话,很容易出现回调地狱的情况

promise

promise 是一个对象,他被创建时是一个不一定已知的值(简单说就是一个容器,里面保存着某个未来才会结束的事件的结果,通常是一个异步操作),promise会和异步操作最终成功还是失败相关联

then方法分别指定resolved状态和rejected状态的回调函数,当异步操作成功(fulfilled)或者失败(rejected)时相应的回调才会被调用,回调返回的结果也是一个promise对象。

promise对象有三个状态:

  1. pending:初始状态,操作执行前的状态
  2. fulfilled:兑现状态,操作成功后的状态
  3. rejected:拒绝状态,操作失败的状态

当promise对象从初始状态被兑现或者拒绝时,promise的then方法中相关回调将会执行,如果promise在绑定回调时已经是fulfilled状态或者rejected状态,then中回调就会立即执行。

new Promise((resolve, reject) => {
    //这里console.log操作会和promise状态关联,成功=>fulfilled,失败rejectde
   console.log('执行完成');
   resolve('执行成功!');
   reject('执行失败!')
}).then(rs => {
  console.log(rs);
}), rj=>{
    console.log(rj)
};

then中接受两个参数,一个是成功的回调(resolved),一个是失败的回调(rejected)。如果需要连续执行两个或者多个异步操作,我们可以通过创造一个promise链来解决,也就是多次调用then方法,并且每个回调都接收前一个成功操作的结果作为输入。

new Promise((resolve,reject)=>{
	console.log('promise1')
	resolve('promise2')
}).then(re=>{
	console.log(re)
    return re
}).then(re2=>{
    console.log(re2)
    return error  // 未定义的变量导致执行失败,promise对象进入rejected状态,catch捕获到错误
}).catch(rj=>{
    console.log(rj.message)
})

通过catch去捕获异常的好处是链式promise中有一个回调抛出错误后仍然可以继续使用后续操作,不需要马上处理这个错误

async/await

async是es6中解决同步异步问题的一个语法糖本质是基于Promise的异步行为,简单理解就是async声明一个异步函数,然后await后面的代码等待异步操作之后才会执行

async函数可能包含0个或者多个await表达式。await表达式会暂停整个async函数的执行进程并出让其控制权,只有当其等待的基于promise的异步操作被兑现或被拒绝之后才会恢复进程。async/await在多层回调嵌套时书写更加直观

// promise
function submit() {
  console.log('submit');
  // 经过俩个校验
  check1().then(res1=>{
    check2(res1).then(res2=>{
       /*
        * 提交请求
        */
    })
  })
}
submit();

// async/await
async function asyncSubmit() {
    let res1 = await check1();
    let res2 = await check2(res1);
        console.log(res1, res2);
        /*
        * 提交请求
        */
}

使用async / await关键字就可以在异步代码中使用普通的try / catch代码块。

async function test() {
  try {
    await new Promise(function (resolve, reject) {
      throw new Error('产生差错了');
    });
  } catch(e) {
      console.log('err', e)
  }
  return await('成功了');
}
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值