视频加载失败

ES6异步Promise

2710 字
14 分钟
ES6异步Promise

Promise 是什么#

认识Promise

  • 异步操作的一种解决方案
  • Promise 是 JavaScript 中用于处理异步操作结果的一种对象。你可以把它理解成一个“未来会得到结果的承诺”。
  • 比如,你点了一份外卖:下单时:结果还没出来 → **等待中(pending)**外卖送到了 → **成功(fulfilled)**商家取消订单 → 失败(rejected)

什么时候用Promise

//网络请求(fetch)
//读取文件
//定时器(setTimeout)
//数据库查询
//没有 Promise 时,代码经常会写成:这种层层嵌套被称为回调地狱(Callback Hell)。
getUser(function(user) {
getOrders(user.id, function(orders) {
getProducts(orders, function(products) {
// ...
});
});
});
//Promise 可以把它改成
getUser()
.then(user => getOrders(user.id))
.then(orders => getProducts(orders))
.then(products => {
console.log(products);
})
.catch(err => {
console.error(err);
});

Promise的基本用法#

实例化构造函数生成对象

//Promise状态一旦改变,就不会变化
const p = new Promise((resolve, reject) => {
//resolve({ name: 'alex' }); //成功
reject(new Error('reason')); //失败
});
//console.log(p); //Promise { <pending> } 等待
p.then(
(data) => {
console.log('success', data); //success { name: 'alex' }
},
(err) => {
console.log('error', err);
},
);

Promise 的三个状态:

  1. Pending(等待中)
  2. Fulfilled(已成功)
  3. Rejected(已失败)

then()#

then() 根据当前 Promise 的状态(fulfilled 或 rejected)执行对应的回调,并返回一个新的 Promise

//Promise状态一旦改变,就不会变化
const p = new Promise((resolve, reject) => {
resolve({ name: 'alex' }); //成功
//reject(new Error('reason')); //失败
});
p.then(
(data) => {
console.log('success', data); //success { name: 'alex' }
///throw new Error('reason111');
return Promise.reject(new Error('reason'));
},
//第二个参数比较少用,错误通常统一交给catch
(err) => {
console.log('error', err);
},
).then(
(data) => {
console.log('success1', data); //success undefined 默认返回的undefined
},
(err) => {
console.log('error1', err);
},
);
  1. 创建一个 Promise 对象p,resolve一个对象{name: ‘alex’ },这里是成功状态
  2. p.then接受两个参数,第一个是成功的时候执行,第二个是失败的时候执行,怎么看成功失败,取决于前面的Promise ,前面的Promise 成功并且返回{ name: ‘alex’ },所以第一个then执行一个参数的函数,所以打印success { name: ‘alex’ },然后返回一个失败的Promise
  3. 第二个then执行的前面Promise ,前面Promise是失败的,所以执行第二个参数’error1’, err

catch()#

catch() 专门用来处理 Promise 链中的失败(rejected)和异常(throw)。

//Promise状态一旦改变,就不会变化
const p = new Promise((resolve, reject) => {
resolve({ name: 'alex' }); //成功
//reject(new Error('reason')); //失败
});
//console.log(p); //Promise { <pending> } 等待
p.then((data) => {
console.log('success', data); //success { name: 'alex' }
///throw new Error('reason111');
return Promise.reject(new Error('reason'));
})
.then((data) => {
console.log('success1', data); //success { name: 'alex' }
})
.catch((err) => {
console.log(err);
});

为什么推荐 catch,而不是 then 的第二个参数?

Promise.resolve(1)
.then(
data => {
throw new Error('boom');//Uncaught Error: boom
},
err => {
console.log('error', err);
}
);

第二个参数没有捕获到;then(success, fail)中的 fail:只能处理当前 Promise 的 reject。不能处理 success 回调里面抛出的异常。

Promise.resolve(1)
.then((data) => {
throw new Error('boom');
})
.catch((err) => {
console.log(err.message); //boom
});
//可以捕获。
  • catch可以捕获前面的错误
  • catch也是返回一个Promise,默认返回undefined,

finally()#

无论 Promise 成功(fulfilled)还是失败(rejected)都会执行的回调。不变化不执行

//基本语法
promise
.then(res => {
console.log("成功:", res);
})
.catch(err => {
console.log("失败:", err);
})
.finally(() => {
console.log("无论成功或失败都会执行");
});
//不会改变 Promise 的结果(重要)
Promise.resolve(1)
.finally(() => {
return 999; // ❌ 没用
})
.then(res => {
console.log(res); // 1
});
//如果 finally 里抛错,会影响结果
Promise.resolve(1)
.finally(() => {
throw new Error("finally error");
})
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err.message); // finally error
});
//常见使用场景
//关闭 loading
loading = true;
fetchData()
.then(data => {
console.log(data);
})
.catch(err => {
console.log(err);
})
.finally(() => {
loading = false;
});
//清理资源
db.query(sql)
.then(result => {
console.log(result);
})
.finally(() => {
db.close();
});

和 then/catch 的区别

方法是否处理成功是否处理失败是否一定执行
then()✔✖✖
catch()✖✔✖
finally()✖(不处理结果)✖(不处理结果)✔

Promise.resolve() 和 Promise.reject()#

是 Promise 提供的两个快速创建已确定状态 Promise 的方法,本质上用来“直接返回成功或失败的 Promise”。

本质:

//Promise.resolve() 是成功状态Promise 的一种简写形式
new Promise(resolve => {
resolve('foo')
});
//等价于
Promise.resolve('foo')

参数:

Promise.resolve:

//Promise.resolve 一般参数 then
// Promise.resolve('foo').then((data) => {
// console.log(data); //foo
// });
//Promise.resolve Promise 参数
const p1 = new Promise((resolve) => {
// setTimeout(() => {
// resolve('我执行了');
// }, 1000);
setTimeout(resolve, 2000, '我执行了');
});
////当Promise.resolve(接收的是 Promise 对象时,直接返回这个Promise对象,什么都不做
Promise.resolve(p1).then((data) => {
console.log(data); //foo
});
//判断
console.log(Promise.resolve(p1) === p1); //true
//Promise.resolve 具有then方法对象
const thenable = {
then(resolve, reject) {
console.log('具有then方法对象'); //具有then方法对象,会直接执行对象里面的then方法
resolve('data');
},
};
Promise.resolve(thenable).then(
(data) => {
console.log(data); //不执行
},
(err) => {
console.log(err); //不执行
},
);

Promise.reject

//Promise.reject 失败状态的一种简写
new Promise((resolve, reject) => {
reject('err');
}).then(
() => {},
(err) => {
console.log(err);
},
);
//等价于
Promise.reject('err1').then(
() => {},
(err) => {
console.log(err);
},
);
//参数问题,不管什么参数都会原封不动向后传递
Promise.reject(p1).then(
() => {},
(err) => {
console.log(err); //Promise { <pending> }
},
);

在then方法中的应用:

new Promise((resolve, reject) => {
resolve(123);
})
.then((data) => {
//Promise.resolve和Promise.reject应用的地方
//console.log(data);
return Promise.reject('reason'); //失败状态
//return data; //等价于return Promise.resolve(data);
})
.then((data) => {
console.log(data); //123 默认返回的undefined
})
.catch((err) => {
console.log(err); //reason
});

Promise.all()#

并发执行多个异步任务,等所有任务都成功后,返回所有结果;如果有一个失败,则立即失败。

基本语法:

//参数:
//接收一个可迭代对象(通常是数组)
//数组里面可以是:Promise 对象或者普通值
//返回:一个新的 Promise。
Promise.all(iterable)

例子:

const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
const p3 = Promise.resolve(3);
Promise.all([p1, p2, p3])
.then(res => {
console.log(res);//[1, 2, 3]
});

模拟多个异步请求

//注意:不是 1 + 2 + 3 = 6 秒;而是:最大时间 3 秒,因为三个请求是并发执行的。
//返回结果顺序:传入数组的顺序返回
function request1() {
return new Promise(resolve => {
setTimeout(() => {
resolve('用户信息');
}, 1000);
});
}
function request2() {
return new Promise(resolve => {
setTimeout(() => {
resolve('订单信息');
}, 2000);
});
}
function request3() {
return new Promise(resolve => {
setTimeout(() => {
resolve('商品信息');
}, 3000);
});
}
Promise.all([
request1(),
request2(),
request3()
]).then(res => {
console.log(res);
});
//一个失败,全部失败
const p1 = Promise.resolve(1);
const p2 = Promise.reject('失败了');
const p3 = Promise.resolve(3);
Promise.all([p1, p2, p3])
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err);
});
//为什么叫"立即失败"
const p1 = new Promise(resolve => {
setTimeout(() => resolve(1), 3000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => reject('错误'), 1000);
});
Promise.all([p1, p2])
.catch(err => {
console.log(err);
});

Promise.race() 和 Promise.allSettled()#

Promise.race

返回一个新的 Promise,谁先 resolve返回成功结果,谁先 reject返回失败结果,不会等其他 Promise。

//谁先成功就返回谁
const p1 = new Promise(resolve => {
setTimeout(() => {
resolve('请求1');
}, 3000);
});
const p2 = new Promise(resolve => {
setTimeout(() => {
resolve('请求2');
}, 1000);
});
Promise.race([p1, p2])
.then(res => {
console.log(res);//请求2
});
//谁先失败也算结束
const p1 = new Promise(resolve => {
setTimeout(() => {
resolve('成功');
}, 3000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('失败');
}, 1000);
});
Promise.race([p1, p2])
.catch(err => {
console.log(err);//失败
});
//实际开发场景:请求超时
//正常请求
fetch('/api/user')
//超时 Promise
const timeout = new Promise((resolve, reject) => {
setTimeout(() => {
reject('请求超时');
}, 5000);
});
//看谁先返回
Promise.race([
fetch('/api/user'),
timeout
])
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err);
});

Promise.allSettled

所有 Promise 都有结果(成功或失败),等待所有 Promise 都执行完。然后返回结果

//基本用法
Promise.allSettled([
Promise.resolve(1),
Promise.reject('错误'),
Promise.resolve(3)
])
.then(res => {
console.log(res);
});
//输出
[
{
status: 'fulfilled',
value: 1
},
{
status: 'rejected',
reason: '错误'
},
{
status: 'fulfilled',
value: 3
}
]

实际开发场景

//页面初始化
//广告失败不应该导致整个页面白屏。
const result = await Promise.allSettled([
getUser(),
getOrders(),
getMessage(),
getAd()
]);
result.forEach(item => {
if (item.status === 'fulfilled') {
console.log(item.value);
} else {
console.log(item.reason);
}
});
//筛选成功结果
const res = await Promise.allSettled(promises);
const data = res
.filter(item => item.status === 'fulfilled')
.map(item => item.value);

Promise 的注意事项#

Promise 这一块很多“坑”其实不是语法问题,而是执行机制 + 微任务队列 + 链式调用规则导致的

一、executor 是同步执行的(最容易误解)

const p = new Promise(() => {
console.log('A');
});
console.log('B');
//输出AB

new Promise(executor) 的 executor 立即同步执行

只有 .then() 才是异步(微任务)

二、then 是异步(微任务)

Promise.resolve().then(() => {
console.log('then');
});
console.log('sync');
//输出sync then

.then/.catch/.finally 都进 微任务队列

当前同步代码执行完才执行

三、Promise 不是“真正并行”,只是异步调度

console.log(1);
setTimeout(() => console.log(2));
Promise.resolve().then(() => console.log(3));
console.log(4);
//1 4 2 2

执行顺序关键点:同步代码 → 1、4;微任务(Promise)→ 3;宏任务(setTimeout)→ 2

四、then 的返回值决定链式行为

//返回普通值 → 自动包装 Promise
Promise.resolve(1)
.then(res => {
return 2;
})
.then(console.log); //2
//返回 Promise → 会“等待”
Promise.resolve(1)
.then(() => {
return new Promise(resolve => {
setTimeout(() => resolve(2), 1000);
});
})
.then(console.log);//会等 1 秒 输出2
//常见坑:忘记 return setTimeout 不影响 Promise 链 没有 return Promise
Promise.resolve()
.then(() => {
setTimeout(() => {
return 123;
}, 1000);
})
.then(console.log);//undefined

五、Promise 一旦确定状态不可改变

const p = new Promise((resolve, reject) => {
resolve('成功');
reject('失败');
});
p.then(console.log);//成功

Promise 状态只能:pending → fulfilled;pending → rejected;一旦确定 → 永远不可更改

六、错误不会自动“传递”,需要 catch

//不写 catch 会:报错未捕获
Promise.resolve()
.then(() => {
throw new Error('错了');
})
.then(() => {
console.log('不会执行');
});
//正确写法
Promise.resolve()
.then(() => {
throw new Error('错了');
})
.catch(err => {
console.log(err.message);
});

七、catch 会“吞错误”

Promise.reject('error')
.catch(err => {
console.log('处理了:', err);
})
.then(() => {
console.log('继续执行');
});
//处理了: error
//继续执行

catch 之后默认返回 resolved Promise

除非你重新 throw

八、Promise.all 有“失败即终止”特性

//直接进入 catch不等 3
Promise.all([
Promise.resolve(1),
Promise.reject('error'),
Promise.resolve(3)
]);

九、Promise 并不会取消任务

const p = fetch('/api');
p.then(...)
  • Promise 本身 无法取消
  • 即使不需要结果,网络请求仍在执行
  • 解决方案:AbortController(fetch);标志位控制

十、then 可以“链式断开”

//正确链式
Promise.resolve(1)
.then(res => {
return Promise.resolve(res + 1);
})
.then(res => {
console.log(res);
});
//但是如果这样
Promise.resolve(1)
.then(res => {
Promise.resolve(res + 1); // ❌ 没 return
})
.then(console.log);//undefined

十一、微任务优先级高于宏任务

setTimeout(() => console.log('timeout'), 0);
Promise.resolve().then(() => console.log('promise'));
console.log('sync');
//sync promise timeout

十二、Promise 不会阻塞线程

Promise.resolve().then(() => {
while(true) {}
});

会卡死主线程,但不是 Promise 阻塞,而是代码阻塞。

十三、finally 不改变结果

Promise.resolve(1)
.finally(() => {
console.log('finally');
})
.then(console.log);//finally 1

finally 不会改变值,除非 throw error

Promise的应用#

把“异步任务”变成“可链式、可组合、可统一处理”的结构

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
<style>
* {
padding: 0;
margin: 0;
}
.centen {
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
}
</style>
</head>
<body>
<div class="centen">
<img
src="https://img1.sycdn.imooc.com/9fa08f6a0833cfc016000682.jpg"
alt=""
id="img"
/>
</div>
<script>
const loadimg = (url) => {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => {
resolve(img);
};
img.onerror = () => {
reject(`图片加载失败 ${url}`);
};
img.src = url;
});
};
const imgDom = document.getElementById('img');
loadimg('https://img1.sycdn.imooc.com/16f88d6a092f8ae717920764.jpg')
.then((data) => {
console.log(data);
setTimeout(() => {
imgDom.src = data.src;
}, 2000);
})
.catch((err) => {
console.log(err);
});
</script>
</body>
</html>

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

ES6异步Promise
https://f.youzi177.cn/posts/20261021011es6-yi-bu-promise/
作者
小封鸭
发布于
2026-10-21
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
小封鸭
小楼一夜听春雨,深巷明朝卖杏花
公告
欢迎来到我的博客。这里主要记录前端全栈和日常内容
分类
标签
最新动态
站点统计
文章
60
分类
3
标签
12
总字数
107,734
运行时长
0 天
最后活动
0 天前
站点信息
构建平台
EdgeOne Pages
博客版本
Firefly v6.16.8
文章许可
CC BY-NC-SA 4.0
文章目录