IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 简析JavaScript异步编程 -> 正文阅读

[JavaScript知识库]简析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

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('成功了');
}
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-04 12:02:05  更:2022-04-04 12:02:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:49:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码