Promise、async和await的使用

一、什么是Promise
        Promise是抽象异步处理对象以及对其进行各种操作的组件。Promise本身是同步的立即执行函数解决异步回调的问题, 当调用 resolve 或 reject 回调函数进行处理的时候, 是异步操作, 会先执行.then/catch等,当主栈完成后,才会去调用执行resolve/reject中存放的方法。

        promise的功能是可以将复杂的异步处理轻松地进行模式化。采用Promise,连续读取多个文件,可以解决回调地狱。

如果说到基于JavaScript的异步处理,我想大多数都会想到利用回调函数。

1.1  resolve
        返回一个promise对象成功的状态,并通知给then方法或catch方法,接下来根据对象的状态决定走哪条路,然后执行后续操作;resolve方法的作用是把promise对象的状态从进行中变成已完成,同时可以向resolve方法传入参数,这个参数会在将来被promise对象的then方法获取;

1.2  reject
       返回一个失败的promise对象;reject方法也是同样的道理,只不过是把promise对象状态变成失败,同时传入的参数会被catch方法获取而已;

        当resolve或reject修改promise对象状态之后,通过检测promise对象的状态,决定执行then还是catch回调方法。在这个过程中:resolve和reject起到的作用是修改对象状态、通知回调函数以及传递回调函数可能需要的参数。这样做的好处就是:把逻辑判断和回调函数分开处理;

2、回调函数 .then 和 .catch 
回调函数的调用是根据对象的状态来完成的:进行中、已完成和失败(pending(进行中)、fullfilled(成功)、rejected(失败)

2.1  Promise.then
1. 得到异步任务的正确结果;

2. 只有Promsie内部的状态落定了,then方法中对应的处理程序才会执行;

3. then方法的强大之处,可以链式调用;

2.2  Promise.catch
进行捕获和处理失败结果;

3、方法 .all() 和 .race() 
3.1  Promise.all()
并发处理多个异步任务(等待机制),所有结果都返回之后,统一打印;
谁跑得慢,以谁为准执行回调;
Promise.all 接收一个 promise对象的数组作为参数,当这个数组里的所有promise对象全部变为resolve或reject状态的时候,它才会去调用 .then 方法;

<template>
	<div>
	  <!-- 当数据未加载完成时显示加载动画 -->
	  <div v-if="!dataLoaded" class="loader">加载中...</div>
	  
	  <!-- 当数据加载完成后显示数据内容 -->
	  <div v-else>
		<h1>数据加载完成</h1>
		<p>数据: {{ data }}</p>
	  </div>
	</div>
  </template>
  
  <script setup>
  import { ref, onMounted } from 'vue';
  
  // 定义一个响应式变量来跟踪数据是否加载完成
  const dataLoaded = ref(false);
  // 定义一个响应式变量来存储异步获取的数据
  const data = ref(null);
  
  // 模拟异步API请求的函数
  function fetchData() {
	return new Promise((resolve) => {
	  // 打印日志,表示开始模拟异步API请求
	  console.log('333 - 开始模拟异步API请求...');           //第二个函数执行
	  
	  // 使用setTimeout模拟2秒的异步操作
	  setTimeout(() => {                           //因为设置了定时器 所以延迟执行打印 
		                                           // 所以 onMounted -》loadData -》 fetchData -》 按顺序第一遍执行   到定时器已经执行完毕
												    // 现在回到 onMounted 从新执行
		// 打印日志,表示异步API请求已完成
		console.log('555 - 异步API请求完成,返回数据...');  //onMounted  已经全都执行完毕  现在按顺序执行打印数据
		
		// 解析Promise,返回模拟的数据
		resolve('这是从异步API获取的数据');
	  }, 2000);
	});
  }
  
  // 异步加载数据的函数
  async function loadData() {
	try {
	  // 打印日志,表示开始加载数据
	  console.log('222 - 开始加载数据...');        //函数的第一个打印
	  
	  // 等待异步API请求完成,并获取结果
	  const result = await fetchData();            //函数里调用的另一个函数
	  
	  // 将获取的数据存储在响应式变量中
	  data.value = result;
	  
	  // 设置数据加载完成的标志
	  dataLoaded.value = true;
	  
	  // 打印日志,表示数据已加载完成并存储
	  console.log('666 - 数据加载完成,并已存储在响应式变量中。');    //onMounted  已经全都执行完毕  现在按顺序执行打印数据
	} catch (error) { 
	  // 如果发生错误,打印错误信息
	  console.error('数据加载失败:', error);
	}
  }
  
  // 组件挂载时的生命周期钩子
  onMounted(() => {
	// 打印日志,表示组件挂载开始,准备加载数据
	console.log('111 - 组件挂载开始,准备加载数据...');  //初始化 执行的第一个打印条件
	
	// 调用loadData函数开始异步加载数据
	loadData();                                     //初始化 执行的第一个函数   执行函数里边的逻辑 和 打印
	
	// 注意:这里的日志会在loadData内部的异步操作之前打印
	// 打印日志,表示组件挂载完成,但数据加载是异步的
	console.log('444 - 组件挂载完成,loadData函数已调用(但数据加载是异步的)。');    //第一轮输出到定时器已经结束   现在继续打印onMounted的值
	
	// 实际的异步数据加载会在之后的某个时间点完成,并更新DOM
  });
  </script>
  
  <style scoped>
  .loader {
	font-size: 1.5em;
	color: gray;
	/* 可以添加CSS动画来增强加载效果 */
  }
  
  h1 {
	color: blue;
  }
  
  p {
	font-size: 1.2em;
  }
  </style>

<template>
	<div>
	  <!-- 当数据未加载完成时显示加载动画 -->
	  <div v-if="!dataLoaded" class="loader">加载中...</div>
	  
	  <!-- 当数据加载完成后显示数据内容和重新加载按钮 -->
	  <div v-else>
		<h1>数据加载完成</h1>
		<p>数据: {{ data }}</p>
		<button @click="reloadData">重新加载数据</button>
	  </div>
	  
	  <!-- 添加一个按钮来手动触发数据加载(初始时隐藏) -->
	  <button v-if="!dataLoaded && canManualLoad" @click="loadData">立即加载数据</button>
	</div>
  </template>
  
  <script setup>
  import { ref, onMounted } from 'vue';
  
  // 定义一个响应式变量来跟踪数据是否加载完成
  const dataLoaded = ref(false);
  // 定义一个响应式变量来存储异步获取的数据
  const data = ref(null);
  // 定义一个响应式变量来控制是否可以手动加载数据(初始为true,用于演示)
  const canManualLoad = ref(true);
  
  // 模拟异步API请求的函数
  function fetchData() {
	return new Promise((resolve) => {
	  // 打印日志,表示开始模拟异步API请求
	  console.log('333 - 开始模拟异步API请求...');
	  
	  // 使用setTimeout模拟2秒的异步操作
	  setTimeout(() => {
		// 打印日志,表示异步API请求已完成
		console.log('444 - 异步API请求完成,返回数据...');
		
		// 解析Promise,返回模拟的数据
		resolve('这是从异步API获取的数据');
	  }, 2000);
	});
  }
  
  // 异步加载数据的函数
  async function loadData() {
	if (!canManualLoad.value) {
	  console.log('手动加载按钮已被禁用,无法加载数据。');
	  return;
	}
	
	try {
	  // 打印日志,表示开始加载数据
	  console.log('222 - 开始加载数据...');
	  
	  // 禁用手动加载按钮,防止重复点击
	  canManualLoad.value = false;
	  
	  // 等待异步API请求完成,并获取结果
	  const result = await fetchData();
	  
	  // 将获取的数据存储在响应式变量中
	  data.value = result;
	  
	  // 设置数据加载完成的标志
	  dataLoaded.value = true;
	  
	  // 重新启用手动加载按钮(在实际应用中可能不需要这一步,这里只是为了演示)
	  // 注意:在实际应用中,如果只需要在组件挂载时加载一次数据,则不需要重新启用按钮
	  setTimeout(() => {
		canManualLoad.value = true;
	  }, 0); // 使用setTimeout来模拟下一个事件循环,以便在数据加载后立即重新启用按钮(仅用于演示)
	  
	  // 打印日志,表示数据已加载完成并存储
	  console.log('555 - 数据加载完成,并已存储在响应式变量中。');
	} catch (error) {
	  // 如果发生错误,打印错误信息,并重新启用手动加载按钮
	  console.error('数据加载失败:', error);
	  canManualLoad.value = true; // 重新启用按钮以便用户可以尝试再次加载
	}
  }
  
  // 组件挂载时的生命周期钩子
  onMounted(() => {
	// 打印日志,表示组件挂载开始,但此时不自动加载数据(因为增加了手动加载的功能)
	// 如果需要自动加载,可以在这里直接调用loadData()
	console.log('111 - 组件挂载完成,但未自动加载数据。可以点击“立即加载数据”按钮来加载。');
  });
  
  // 定义一个函数来处理重新加载数据的操作
  function reloadData() {
	// 在重新加载之前,重置数据加载状态和数据
	dataLoaded.value = false;
	data.value = null;
	
	// 重新调用loadData函数来加载数据
	loadData();
  }
  </script>
  
  <style scoped>
  .loader {
	font-size: 1.5em;
	color: gray;
	/* 可以添加CSS动画来增强加载效果 */
  }
  
  h1 {
	color: blue;
  }
  
  p {
	font-size: 1.2em;
  }
  
  button {
	margin-top: 10px;
	padding: 5px 10px;
	font-size: 1em;
  }
  </style>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值