前端进阶 - 异步

异步

1. 什么是单线程,和异步的关系

1.1 单线程

单线程是指在JavaScript中,只有一个主线程执行代码,意味着同时只能做一件事情。如果有耗时的任务,例如循环运算或者执行alert弹窗,会导致JS执行和DOM渲染暂时卡顿,影响用户体验。

示例代码:

// 循环运行期间, JS 执行和 DOM 渲染暂时卡顿
var i, sum = 0;
for (i = 0; i < 1000000; i++){
	sum += i;
}
console.log(sum);

// alert 不处理, JS 执行 和 DOM 渲染暂时卡顿
console.log(1);
alert('hello');
console.log(2);

1.2 异步解决方案

由于单线程的限制,为了避免DOM渲染冲突,JS引入异步解决方案,让一些耗时任务在后台执行,不阻塞主线程。常见的异步操作有定时器(setTimeoutsetInterval)、网络请求(Ajax)和事件处理(addEventListener)等。

示例代码:

console.log(100);
setTimeout(function(){
	console.log(200);
}, 1000);
console.log(300);
console.log(400);
/*
输出:
100
300
400
200
*/

异步方案虽然解决了一些问题,但也带来了新的挑战,如代码的可读性较差,回调函数嵌套导致代码难以维护等问题。

2. Event Loop(事件轮询)

2.1 什么是 Event Loop

事件轮询是JavaScript实现异步的具体解决方案。在JS中,同步代码会直接执行,异步函数会先放入异步队列中,待同步函数执行完毕后,会轮询执行异步队列中的函数。

2.2 事件轮询的过程

  1. 执行同步代码,直至遇到第一个异步函数。
  2. 将异步函数放入异步队列,等待同步代码执行完毕。
  3. 同步代码执行完毕后,开始轮询异步队列中的函数,逐个执行。

2.3 示例代码

console.log(100);
setTimeout(function(){
	console.log(200);
}, 0); // 0ms延迟,但仍会被放入异步队列,等待同步代码执行完毕
console.log(300);
console.log(400);
/*
输出:
100
300
400
200
*/

3. 使用 JQuery 的 Deferred

3.1 JQuery 1.5 的变化

在 JQuery 1.5 之前,异步操作使用$.ajax的回调函数进行处理,如下所示:

var ajax = $.ajax({
	url: 'data.json',
	success: function(){
		console.log('success');
	},
	error: function(){
		console.log('error');
	}
});

console.log(ajax); // 返回一个XHR对象

而在 JQuery 1.5 之后,引入了 Deferred 对象,简化了异步操作的写法,如下所示:

var ajax = $.ajax('data.json');
ajax.done(function(){
	console.log('success');
}).fail(function(){
	console.log('error');
}).done(function(){
	console.log('success2');
});

console.log(ajax); // 返回一个 Deferred 对象

3.2 JQuery Deferred 的特性

  • JQuery Deferred 是 Promise 的前身,功能和使用方式与 Promise 类似。
  • JQuery Deferred 与 Promise 可以同时使用,但不推荐混用。

4. Promise 的基本使用和原理

4.1 Promise 基本语法回顾

Promise 是 ES6 中引入的异步编程解决方案,它包含三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。基本使用如下:

const promise = new Promise((resolve, reject) => {
  // 异步操作
  if (/* 异步操作成功 */) {
    resolve(result); // 将结果传递给 then
  } else {
    reject(error); // 将错误传递给 catch
  }
});

promise.then((result) => {
  // 处理成功的结果
}).catch((error) => {
  // 处理失败的结果
});

4.2 异常捕获

使用 Promise 可以方便地捕获异步操作中的异常,通过 catch 方法捕获 reject 的结果。

4.3 多个串联

Promise 可以链式调用,实现多个异步操作的串联,提高代码的可读性和维护性。

4.4 Promise.all 和 Promise.race

Promise.all可以接收一个由多个 Promise 组成的数组,当数组中所有的 Promise 都成功时,返回一个包含所有结果的数组;如果其中一个 Promise 失败,则返回失败的结果。Promise.race同样接收一个 Promise 数组,但是只要有一个 Promise 状态发生变化(成功或失败),则返回该 Promise 的结果。

4.5 Promise 标准

Promise 规范是对 Promise 实现的标准,有助于不同环境下(如浏览器、Node.js)的统一使用。

5. async/await(ES7)

5.1 async/await 语法

async/await 是 ES7 中的特性,是对 Promise 的进一步封装,使异步操作更加直观和易读。使用 async/await 可以实现类似同步写法的异步操作。

示例代码:

// 最直接的同步写法
const load = async function () {
    const result1 = await loadImg(src1);
    console.log(result1);
    const result2 =  await loadImg(src2);
    console.log(result2);
}
load();

5.2 async/await 特点

  • 使用了 Promise,

但是不和 Promise 冲突,更加直观易读。

  • 完全是同步的写法,再也没有回调函数,避免了回调地狱。
  • async/await 改变不了 JavaScript 单线程、异步的本质。

6. 总结当前 JS 异步解决方案

目前,JavaScript 异步解决方案有以下几种:

  1. JQuery Deferred
  2. Promise
  3. async/await

其中,async/await 是最直观和易读的异步编程方式,但并不改变 JavaScript 单线程、异步的本质。虽然还有其他解决方案,如 Generator,但因为其复杂性和开发成本较高,现在更推荐使用 async/await 或其他现代的异步解决方案。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橘子☆心酸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值