欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > IT业 > 想品客老师的第十二天:异步和promise(下)

想品客老师的第十二天:异步和promise(下)

2025/2/13 7:03:35 来源:https://blog.csdn.net/Au_ust/article/details/145592577  浏览:    关键词:想品客老师的第十二天:异步和promise(下)

介绍Promise其他API

Promise.resolve

表示成功状态

       Promise.resolve('我是成功状态').then(value=>{
console.log('进入成功状态') },lose=>{console.log('进入失败状态')})

Promise.reject

表示失败状态,使用的频率比成功的少一点

Promise.reject的巧用:可以抛出错误

  new Promise((resolve, reject) => {resolve("后盾人");}).then(value => {//这里没有写对应的reject的方法,所以会出错if (value != "成功") {// throw new Error("fail");return Promise.reject("参数错误");}}).catch(error => {console.log(error + "fail");});

Promise.all

当所有输入的 Promise 都被resloved时,返回的 Promise 也将被resloved(即使传入的是一个空的可迭代对象),并返回一个包含所有兑现(resloved)值的数组。

如果输入的任何 Promise 被拒绝,则返回的 Promise 将被拒绝,并带有第一个被拒绝的原因。

 const first=new Promise((resolve,reject)=>{setTimeout(()=>{resolve('第一个异步')},1000)})//需等待一秒const second=new Promise((reslove,reject)=>{reslove('第二个异步')})//立即可以返回Promise.all([first,second]).then(res=>{console.log(res)//等待一秒再执行then})

Promise.all 接收一个包含多个 Promise 的数组(这里是 [first, second]),并等待所有 Promise 都解决(resolved)。

根据用户批量获取用户资料

 function getUsers(names) {let promises = names.map(name => {return ajax(`http://localhost:8888/php/user.php?name=${name}`);});return Promise.all(promises);//这里可以一次获取多个数据,一个数据获取失败就返回失败()rejected}getUsers(["后盾人"]).then(users => {console.log(users);});

我好像大概懂这玩意的意思了,但是我搭的服务器我忘了Nginx 配置文件路径在哪了。。。所以就这样吧

AJAX(Asynchronous JavaScript and XML)是指通过 JavaScript 异步地向服务器请求数据,而无需刷新页面。这使得网页可以在不重新加载整个页面的情况下更新部分内容

ajax(http://localhost:8888/php/user.php?name=${name}`)` 这行代码实际上是一个 异步 HTTP 请求,通过 GET 方法向服务器发起请求,向 http://localhost:8888/php/user.php 发送一个带有 name 参数的请求。

Promise.allSettled

和all不同,all是只返回全部resolved的,而allSettled是都返回,但是resolved的返回,rejected的也返回,并且作以区分

    const p1 = new Promise((resolve, reject) => {reject("rejected");});const p2 = new Promise((resolve, reject) => {resolve("resolved");});Promise.allSettled([p1, p2]).then(results => {console.log(results);});

Promise.race

发送多个Promise,哪个返回的快选哪个

 const first = new Promise((resolve, reject) => {setTimeout(() => {resolve("第一个异步,我比较快");}, 200);});const second = new Promise((resolve, reject) => {setTimeout(() => {resolve("第二个异步,我比较慢");}, 1000);});Promise.race([first,second]).then(results => {console.log(results);}).catch(msg => {console.log(msg);});

返回慢的在这里就不管他

Promise队列

队列原理

 下一个Promise等上一个Promise完成后开始执行,其实之前接触过,就是返回Promise的时候,先执行这个Promise,再走外层的Promise

    let promise = Promise.resolve("后盾人");promise = promise.then(v => {return new Promise(resolve => {setTimeout(() => {console.log(1);resolve();}, 1000);});});promise.then(v => {return new Promise(resolve => {setTimeout(() => {console.log(2);resolve();}, 1000);});});

只要then每次返回的是Promise,就可以形成队列

使用Map实现Promise队列

function queue(num){let promise=Promise.resolve()num.map(v=>{promise=promise.then(_=>{return new Promise(resolve=>{setTimeout(()=>{console.log(v)resolve()},1000)})})})
}
queue([1,2,3,4,5])

将任务p1和任务p2传入Promise 队列

function queue(num){let promise=Promise.resolve()num.map(v=>{promise=promise.then(_=>{return v()})})}function p1() {return new Promise(resolve => {setTimeout(() => {console.log("p1");resolve();}, 1000);});}function p2() {return new Promise(resolve => {setTimeout(() => {console.log("p2");resolve();}, 1000);});}queue([p1, p2]);

定时器模拟执行时间

reduce封装Promise队列

reduce 遍历数组中的每个元素 n,每次遍历时,返回一个新的 Promise,并将其链接到前一个 Promise 上每个 Promise 会延迟 1 秒执行,打印当前值 n,然后解决 Promise

function queue(arr){arr.reduce((promise,n)=>{return promise.then(_=>{return new Promise(resolve => {setTimeout(() => {console.log(n);resolve();}, 1000);});});}, Promise.resolve());//设置reduce的初始值为一个已经resolved的promise}queue([1, 2, 3, 4]);

神奇的reduce!

使用队列渲染数据

我没搭建服务器,就这么看吧:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><title>后盾人</title></head><body></body><script>class User {ajax(user) {let url = `http://localhost:8888/php/user.php`;return new Promise((resolve, reject) => {let xhr = new XMLHttpRequest();xhr.open("GET", `${url}?name=${user}`);xhr.send();xhr.onload = function() {if (this.status == 200) {resolve(JSON.parse(this.response));} else if (this.status == 404) {reject(new HttpError("用户不存在"));} else {reject("加载失败");}};xhr.onerror = function() {reject(this);};});}render(users) {users.reduce((promise, user) => {return promise.then(_ => {return this.ajax(user);}).then(user => {return this.view(user);});}, Promise.resolve());}view(user) {return new Promise(resolve => {let h2 = document.createElement("h2");h2.innerHTML = user.name;document.body.appendChild(h2);resolve();});}}new User().render(["后盾人", "向军"]);</script>
</html>

async与await语法糖

async/await 通过同步的方式执行异步任务

可以看到async 关键字声明了一个异步函数。

async function example() {return '我是async'
}
example().then(v=>{console.log(v)})//我是async

这个方法避免了普通Promise的层层回调的结构

await 会暂停异步函数的执行,直到 Promise 完成(resolved 或 rejected),在 await 后面的代码会等待 Promise 完成后再执行。

   async function hd() {let name = await new Promise(resolve => {setTimeout(() => {resolve("后盾人");}, 2000);});let site = await new Promise(resolve => {setTimeout(() => {resolve(name + "houdunren.com");}, 2000);});console.log(site)}hd()//后盾人houdunren.com

如果不用这个语法糖,则需要使用之前学的promise的链式调用:

  function hd() {new Promise(resolve => {setTimeout(() => {resolve("后盾人");}, 2000);}).then(name => {return new Promise(resolve => {setTimeout(() => {resolve(name + "houdunren.com");}, 2000);});}).then(site => {console.log(site);})}hd()//后盾人houdunren.com

这样需要频繁的返回new Promise

特性async/await 写法Promise 链式调用写法
代码风格更像同步代码,易于阅读和维护嵌套较多,代码结构复杂
错误处理使用 try/catch使用 .catch
适用场景适合多个异步操作按顺序执行适合简单的异步操作
可读性

在 async 函数中,return 的值会自动被包装成一个 Promise

那你就要问了:为什么这么写,居然是字符串类型

async function example() {return '我是async';
}example().then(v => {console.log(typeof v); //string
});

因为async函数返回的 Promise 的解决值是 '我是async',而不是 Promise 本身;.then 中的回调函数接收的是 Promise 的解决值,而不是 Promise 对象

所以example().then()里,这个then()里接收到的返回值也就是v,是Promise的【解决值】,也就是【我是async】,而不是promise对象本身,【我是async】是个字符串嘛,所以是string

解决值(resolved value)

可以这么验证是不是promise

async function example() {return '我是async';
}const result = example();
console.log(result instanceof Promise); // 输出: true

async/await执行异步请示栗子(没搭建服务器照例摆个代码在这里)

 async function get(name) {let host = "http://localhost:8888/php";let user = await ajax(`${host}/user.php?name=${name}`);let lessons = await ajax(`${host}/houdunren.php?id=${user.id}`);console.log(lessons);}get("后盾人");

async写延迟函数

async function sleep(delay=2000) {return new Promise(resolve=>{setTimeout(()=>{resolve()},delay)})
}
async function show() {for(const user of ['我是1','我是2']){await sleep()//不加await会直接打印内容,不会延迟//因为await要等待new Promise返回过来console.log(user)}
}
show()

await写进度条

进度条随着数据的读取加载

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><title>后盾人</title></head><body><style>div {height: 50px;width: 0px;background: #8e44ad;display: flex;justify-content: center;align-items: center;font-size: 30px;color: #fff;}</style><div id="loading">0%</div></body><script src="js/ajax.js"></script><script>function query(name) {return ajax(`http://localhost:8888/php/user.php?name=${name}`);}(async () => {let users = ["后盾人", "李四", "赵六"];for (let i = 0; i < users.length; i++) {let user = await query(users[i]);let progress = ((i + 1) / users.length) * 100;loading.style.width = progress + "%";loading.innerHTML = Math.round(progress) + "%";}})()</script>
</html>

ajax:

class ParamError extends Error {constructor(msg) {super(msg);this.name = "ParamError";}
}
class HttpError extends Error {constructor(msg) {super(msg);this.name = "HttpError";}
}
function ajax(url) {return new Promise((resolve, reject) => {// loading.style.display = "block";if (!/^http/.test(url)) {throw new ParamError("请求地址格式错误");}let xhr = new XMLHttpRequest();xhr.open("GET", url);xhr.send();xhr.onload = function() {if (this.status == 200) {resolve(JSON.parse(this.response));} else if (this.status == 404) {// throw new HttpError("用户不存在");reject(new HttpError("用户不存在"));} else {reject("加载失败");}};xhr.onerror = function() {reject(this);};});
}

php:

<?php
header("Access-Control-Allow-Origin:*");
$users = [['id' => 1, 'name' => '后盾人', 'email' => 'admin@houdunren.com'],['id' => 2, 'name' => '向军', 'email' => '2300071698@qq.com'],['id' => 3, 'name' => '李四', 'email' => 'lisi@qq.com'],['id' => 4, 'name' => '王五', 'email' => 'wangwu@qq.com'],['id' => 5, 'name' => '赵六', 'email' => 'zaoliu@qq.com'],
];
//根据用户名获取用户
if (isset($_GET['name'])) {$response = array_filter($users, function ($user) {return $user['name'] == $_GET['name'];});if ($response) {die(json_encode(array_pop($response)));} else {die(header('HTTP/1.1 404'));}
}
//根据编号获取用户列表
if (isset($_GET['id'])) {$ids = explode(',', $_GET['id']);$response = array_filter($users, function ($user) use ($ids) {return in_array($user['id'], $ids);});die(json_encode($response));
}

类与await的结合

如果一个类里面包含then方法,那么他会包装成promise

   class User {constructor(name) {this.name = name;}then(resolve, reject) {let user = ajax(`http://localhost:8888/php/user.php?name=${this.name}`);resolve(user);}}async function get() {let user = await new User("后盾人");console.log(user);}get();

User类里的then方法的存在使得User的实例可以被await使用,因为await会尝试调用对象的then方法,在异步函数get里,await会等待new User()返回的实例,并接受这个返回的数据,这个返回的数据就是ajax请求的数据,也就是user

把数据处理封装在内部

如果直接封装在内部:

  class User {get() {let user = ajax(`http://localhost:8888/php/user.php?name=${this.name}`);user.name+='-houdunren.com'console.log(user);return user}}new User().get('荷叶饭');

发现user.name是undefined,为什么?

因为ajax是异步的,下面是user.name='-houdunren.com'是同步的,按照执行顺序来说是先同步再异步,所以先进行了user.name='-houdunren.com',此时ajax还没申请到数据,所以为undefined

对上面的代码做更改

  class User {async get(name) {let user = await ajax(`http://localhost:8888/php/user.php?name=${name}`);user.name += "-houdunren.com";return user;}}new User().get("后盾人").then(user => {console.log(user);});

要等待异步先完成哦

async和await的多种声明

标准函数声明

async function fetchData() {const response = await fetch('https://api.example.com/data');const data = await response.json();return data;
}fetchData().then(data => console.log(data));

函数表达式就是将async赋值给一个变量

箭头函数也可以:

const fetchData = async () => {}

在对象中声明 async 方法:

const object = {async fetchData() {}
};api.fetchData().then(data => console.log(data));

在类里声明:

class ApiClient {async fetchData() {}
}const client = new ApiClient();
client.fetchData().then(data => console.log(data));

async基本错误处理

也可以用throw和catch:

   async function hd(name) {// throw new Error("fail")//也可以return ajax(`http://localhost:8888/php/user.php?name=${name}`);}hd("后盾人视频").then(user => {console.log(user);}).catch(error => {console.log("Error" + error);});

标准的await错误处理流程

接收到错误的处理,可以使用try、catch,写里面和写外面都可以

 async function hd(name) {let user = await ajax(`http://localhost:8888/php/user.php?name=${name}`);let lessons = await ajax(`http://localhost:8888/php/houdunren.php?id=${user.id}`);return lessons;}hd("后盾人教程").then(lessons => {console.log(lessons);}).catch(error => {alert(error.message);});
    async function hd(name) {try{let user = await ajax(`http://localhost:8888/php/user.php?name=${name}`);let lessons = await ajax(`http://localhost:8888/php/houdunren.php?id=${user.id}`);return lessons;
}catch(error){alert(error.message)
}}hd("后盾人教程").then(lessons => {console.log(lessons);})

有错误一定要处理

await并行执行技巧

Promise 是异步的,它们的执行不会阻塞主线程,

当调用 p1() 和 p2() 时,两个 Promise 会立即开始执行,并分别在 2 秒后解决。

   function p1() {return new Promise(resolve => {setTimeout(() => {resolve("houdunren");}, 2000);});}function p2() {return new Promise(resolve => {setTimeout(() => {resolve("hdcms");}, 2000);});}async function hd() {let res = await Promise.all([p1(), p2()]);//达到并行效果console.log(res);
  • 因为 p1 和 p2 的 setTimeout 都是 2 秒,所以它们会在几乎相同的时间完成。

  • 总执行时间约为 2 秒(并行执行),而不是 4 秒(串行执行是4秒)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com