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 的三个状态:
- Pending(等待中)
- Fulfilled(已成功)
- 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); },);- 创建一个 Promise 对象p,resolve一个对象{name: ‘alex’ },这里是成功状态
- p.then接受两个参数,第一个是成功的时候执行,第二个是失败的时候执行,怎么看成功失败,取决于前面的Promise ,前面的Promise 成功并且返回{ name: ‘alex’ },所以第一个then执行一个参数的函数,所以打印success { name: ‘alex’ },然后返回一个失败的Promise
- 第二个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 });//常见使用场景//关闭 loadingloading = 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')//超时 Promiseconst 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');//输出ABnew 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 的返回值决定链式行为
//返回普通值 → 自动包装 PromisePromise.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 PromisePromise.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不等 3Promise.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 1finally 不会改变值,除非 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>文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!














