Javascript控制异步代码的几种方法

setTimeout

setTimeout的核心作用流程

1. 主线程移交任务

  • 主线程执行到setTimeout(callback, delay)时,立即callback函数和delay延迟时间交给浏览器的定时器模块(Web API),主线程继续执行后续同步代码(不阻塞)。

2. 定时器倒计时

  • 浏览器的定时器线程开始计时,独立于主线程运行,等待指定的delay时间(如 1000ms)。

3. 回调进入任务队列

  • 当倒计时结束,定时器线程将callback函数推入宏任务队列(Task Queue),此时回调函数仍未执行,只是进入排队状态。

4. 事件循环调度执行

  • 主线程的同步代码全部执行完毕后(调用栈为空),事件循环(Event Loop)检查任务队列:
  • 优先清空微任务队列(如 Promise 回调)。
  • 从宏任务队列中取出callback,推入调用栈,由主线程执行。

事件驱动

除了setTimeout,Javascript还可以通过事件驱动来控制异步代码的执行,基于几个基本概念:

  1. 事件循环(Event Loop): JavaScript 运行时的核心机制,不断检查是否有待处理的事件
  2. 事件队列(Event Queue): 存储待处理的事件和回调函数
  3. 事件发射器(Event Emitter): 产生事件的对象
const button = document.getElementById('myButton');

// 按钮作为事件发射器Event Emitter,我们给它添加监听器
button.addEventListener('click', function(event) {
 console.log('按钮被点击了!', event);
});

发布—订阅设计模式

发布—订阅并不是Javascript中的原生概念,而是一种设计模式,又称观察者模式。

运行机制:创建一个“信号中心”,某个任务执行完成,就向信号中心“发布”(publish)一个信号,其他任务可以向信号中心“订阅”(subscribe)这个信号,从而知道什么时候自己可以开始执行。

// 极简发布-订阅实现
class EventEmitter {
 constructor() {
 this.events = {};
  }

 // 订阅事件
 on(event, callback) {
 if (!this.events[event]) {
 this.events[event] = [];
    }
 this.events[event].push(callback);
  }

 // 发布事件
 emit(event, ...args) {
 if (this.events[event]) {
 this.events[event].forEach(callback => callback(...args));
    }
  }

 // 取消订阅
 off(event, callback) {
 if (this.events[event]) {
 this.events[event] = this.events[event].filter(cb => cb !== callback);
    }
  }
}

// 使用示例
const emitter = new EventEmitter();

// 订阅者1
const subscriber1 = (data) => {
 console.log('Subscriber1 received:', data);
};

// 订阅者2
const subscriber2 = (data) => {
 console.log('Subscriber2 received:', data);
};

// 订阅事件
emitter.on('message', subscriber1);
emitter.on('message', subscriber2);

// 发布事件
emitter.emit('message', 'Hello World!'); 
// 输出:
// Subscriber1 received: Hello World!
// Subscriber2 received: Hello World!

// 取消订阅
emitter.off('message', subscriber1);

// 再次发布
emitter.emit('message', 'Goodbye!');
// 输出:
// Subscriber2 received: Goodbye!

Promise

当多个异步操作需要顺序执行时,传统的回调写法会形成层层嵌套,导致难以阅读和维护。Promise为了解决Javascript中的“回调地狱”问题应运而生。

// 传统写法
step1(function (value1) {
 step2(value1, function(value2) {
 step3(value2, function(value3) {
 step4(value3, function(value4) {
 // ...
      });
    });
  });
});

// Promise 的写法
(new Promise(step1))
  .then(step2)
  .then(step3)
  .then(step4);

Promise的状态转换

pending(等待中)

/ \

fulfilled rejected

(成功) (失败)

Promise的创建模板

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己实现。

const promise = new Promise((resolve, reject) => {
 // 这里是你的异步操作
 
 if (/* 操作成功 */) {
 resolve('成功的结果'); // 触发.then()
  } else {
 reject('失败的原因'); // 触发.catch()
  }
});

Promise极简示例

// 创建Promise
const weatherPromise = new Promise((resolve, reject) => {
 const isSunny = Math.random() > 0.5;
 
 setTimeout(() => {
 isSunny ? resolve('晴天') : reject('下雨');
  }, 1000);
});

// 使用Promise
weatherPromise
  .then(weather => console.log(`今天是${weather},去野餐!`))
  .catch(reason => console.log(`因为${reason},取消野餐`));

Promise“升级版”——async和await

async/await 是 JavaScript 处理异步操作的语法糖,它是基于 Promise 的,但让异步代码写起来更像同步代码,更易读和维护。

async关键字标记一个函数为“异步函数”,特性:

  • 自动将返回值包装成 Promise
  • 函数内可以使用 await
// Promise写法
function getUser() {
 fetch('/user')
    .then(response => response.json())
    .then(user => console.log(user))
    .catch(error => console.error(error));
}

// async/await写法
async function getUser() {
 try {
 const response = await fetch('/user');
 const user = await response.json();
 console.log(user);
  } catch (error) {
 console.error(error);
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值