介绍
Promise/A+规范
- 存在三个状态:等待(
pending
),执行中(fulfilled
),失败(rejected
) - 初始态为等待态,可转换为执行中和失败
- 执行中不可转换为其它状态,且必须有一个不可变的终值(
value
) - 失败状态不可转换为其它状态,且必须有一个不可变的原因(
reason
) - 必须提供一个
then
方法,以供访问其当前值,终值以及原因 then
方法提供两个参数:onFulfilled
和onRejected
onFulfilled
和onRejected
如果不是函数类型,必须忽略- 如果
executor
执行报错,直接执行reject
- 不同的
promise
可以相互套用
更多参考 promise/A+
Promise 起源与用途
Promise
最早在社区提出和实现,在es6
写入了语言标准Promise
是异步编程的解决方案,比传统的回调函数方式更加合理更加强大更加有呀- 语法上:使用
Promise
构造函数对异步操作进行封装以生成Promise
实例 - 功能上:
Promise
对象用来封装一个异步操作并提供统一的 API,使用各种异步操作都可以用同步的方式进行处理
常用场景
fs
文件操作
require("fs").readFile("./index.html", (err, data) => {});
Ajax
操作
$.get("/api/getUser", (data) => {});
- 定时器
setTimeout(() => {}, 1000);
为什么使用Promise
- 支持链式调用,将异步操作以同步操作的流程表达出来
- 可以解决回调地狱
// 回调地狱典型场景
asyncFunc1(opt, (...args1) => {
asyncFunc2(opt, (...args2) => {
asyncFunc3(opt, (...args3) => {
asyncFunc4(opt, (...args4) => {
//TODO: some opt
});
});
});
});
-
指定回调函数的方式更加灵活
- 传统方式:必须在启动异步任务之前指定
- Promise:可以随时监听任务的状态,随时指定回调函数,一个或者多个
-
Promise
提供了统一的 api,使得控制异步操作更加容易
Promise
优缺点
优点
- 对象不受外界影响
- 一旦状态改变,就不会再发生变化
let promise = new Promise(function (resolve, reject) {
console.log("Promise");
resolve();
});
promise.then(function () {
console.log("resolved.");
});
console.log("Hi!");
结果:
Promise
Hi!
resolved.
缺点
- 一旦新建,立即执行,无法中途取消
Promise
内部跑出的错误,无法反映到外部pedding
状态时无法知道进展到哪一个阶段
Promise
使用
实例创建
const promise = new Promise((resolve, reject) => {
if (/*成功*/) {
resolve(value)
} else {
reject(error)
}
})
resolve
函数:将Promise
对象的状态从"未完成"变成"成功"(pedding
=>fulfilled
),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去reject
函数:将Promise
对象的状态从"未完成"变成"失败"(pedding
=>reject
),在异步操作失败时调用,并将异步操作报错的错误作为参数传递出去
例子(异步加载图片)
<body>
<div id="app"></div>
</body>
<script>
function loadImageAsync(url) {
return new Promise(function (resolve, reject) {
const image = new Image();
image.onload = function () {
resolve(image);
};
image.onerror = function () {
reject(new Error("无法加载图片 " + url));
};
image.src = url;
});
}
var img = loadImageAsync("http://www.pic.uvdream.cn/1616131986开发计划.png");
img.then((res) => {
console.log(res);
var d = document.getElementById("app");
d.appendChild(res);
});
</script>
Promise.prototype.then()
promise.then(
function (value) {
// success
},
function (error) {
// failure
}
);
Promise.prototype.catch()
promise
.then(
function (value) {
// success
},
function (error) {
// failure
}
)
.catch(function (error) {
console.log("发生错误", error);
});
如果 then()方法中出现错误也会被 catch()捕捉
const promise = new Promise(function (resolve, reject) {
throw new Error("test");
});
promise.catch(function (error) {
console.log(error);
});
也可以下面写法
// 写法一
const promise = new Promise(function (resolve, reject) {
try {
throw new Error("test");
} catch (e) {
reject(e);
}
});
promise.catch(function (error) {
console.log(error);
});
// 写法二
const promise = new Promise(function (resolve, reject) {
reject(new Error("test"));
});
promise.catch(function (error) {
console.log(error);
});
如果
Promise
状态已经变成resolved
,再抛出错误是无效的
const promise = new Promise(function (resolve, reject) {
resolve("ok");
throw new Error("test");
});
promise
.then(function (value) {
console.log(value);
})
.catch(function (error) {
console.log(error);
});
以上代码是不会抛出错误的
Promise.resolve()
返回成功或者失败的Promise
对象
Prmose.reject()
返回一个失败的Promise
对象
Promise.all()
方法将多个
Promise
实例,包装成一个新的Promise
实例
const p= Promise.all([p1,p2,p3])
p 的状态由 p1,p2,p3 决定
- 只有 p1,p2,p3 的状态都编程
fulfilled
,p 的状态才会编程fulfilled
,此时 p1,p2,p3 的返回值组成一个数组,传递给 p 的回调函数 - 只要 p1,p2,p3 之中有一个
rejected
,p 的状态就变成rejected
,此时第一个rejected
的实例的返回值,会传递给 p 的回调函数
例子
let p1 = Promise.resolve(1);
let p2 = Promise.resolve(2);
let p3 = Promise.reject(3);
const res = Promise.all([p1, p2, p3]); //此时输出为 [[PromiseState]]是rejected,[[PromiseResult]]是3的Promise
const res = Promise.all([p1, p2]); //此时输出为 [[PromiseState]]是fulfilled,[[PromiseResult]]是[1,2]的Promise
Promise.prototype.finally()
finally()
方法用于指定不管Promise
对象最后状态如何,都会执行的操作,
finally()
其实就是then()
方法的特例
promise.finally(() => {
//...
});
// 等同于
promise.then(
(result) => {
//...
return result;
},
(error) => {
//...
throw error;
}
);
Promise.race()
同样将多个
Promise
实例包装成一个新的Promise
实例`
Promise.allSettled()
接受一组
Promise
实例作为参数,包装秤一个新的Promise
实例,只有等到所有这些实例都返回结果,不管是fulfilled
还是rejected
,包装实例才会结束
Promise.any()
该方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例返回。只要参数实例有一个变成
fulfilled
状态,包装实例就会变成fulfilled
状态;如果所有参数实例都变成rejected
状态,包装实例就会变成rejected
状态。
手写 Promise
ES6
class Promise {
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
// 保存promise状态
this.status = Promise.PENDING;
// 保存promise结果
this.value = null;
// 解决setTimeOut问题,保存异步回调列表
this.callbacks = [];
try {
executor(this.resolve.bind(this), this.rejected.bind(this));
} catch (error) {
this.rejected(error);
}
}
resolve(value) {
if (this.status === Promise.PENDING) {
this.status = Promise.FULFILLED;
this.value = value;
setTimeout(() => {
// 解决setTimeOut问题
this.callbacks.map((callback) => {
callback.onResolved(value);
});
});
}
}
rejected(value) {
if (this.status === Promise.PENDING) {
this.status = Promise.REJECTED;
this.value = value;
setTimeout(() => {
// 解决setTimeOut问题
this.callbacks.map((callback) => {
callback.onRejected(value);
});
});
}
}
then(onResolved, onRejected) {
if (typeof onResolved !== "function") {
// then()的穿透解决
onResolved = (value) => value;
}
if (typeof onRejected !== "function") {
// then()的穿透解决
onRejected = (value) => value;
}
let promise = new Promise((resolve, rejected) => {
if (this.status === Promise.PENDING) {
this.callbacks.push({
onResolved: (value) => {
this.parse(promise, onResolved(value), resolve, rejected);
// try {
// let result = onResolved(value)
// if (result instanceof Promise) {
// result.then(resolve, rejected)
// } else {
// resolve(result)
// }
// } catch (error) {
// // onRejected(error)
// rejected(error)
// }
},
onRejected: (value) => {
this.parse(promise, onRejected(value), resolve, rejected);
// try {
// let result = onRejected(value)
// if (result instanceof Promise) {
// result.then(resolve, rejected)
// } else {
// resolve(result)
// }
// } catch (error) {
// // onRejected(error)
// rejected(error)
// }
},
});
}
if (this.status === Promise.FULFILLED) {
setTimeout(() => {
this.parse(promise, onResolved(this.value), resolve, rejected);
// try {
// let result = onResolved(this.value)
// if (result instanceof Promise) {
// result.then(resolve, rejected)
// } else {
// resolve(result)
// }
// } catch (error) {
// // onRejected(error)
// rejected(error)
// }
});
}
if (this.status === Promise.REJECTED) {
setTimeout(() => {
this.parse(promise, onRejected(this.value), resolve, rejected);
// try {
// let result = onRejected(this.value)
// if (result instanceof Promise) {
// result.then(resolve, rejected)
// } else {
// resolve(result)
// }
// } catch (error) {
// // onRejected(error)
// rejected(error)
// }
});
}
});
return promise;
}
parse(promise, result, resolve, rejected) {
if (promise === result) {
throw new Error("不能返回promise");
}
try {
// let result = onResolved(this.value)
if (result instanceof Promise) {
result.then(resolve, rejected);
} else {
resolve(result);
}
} catch (error) {
// onRejected(error)
rejected(error);
}
}
static resolve(value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(resolve, reject);
} else {
resolve(value);
}
});
}
static reject(value) {
return new Promise((resolve, reject) => {
reject(value);
});
}
static all(promises) {
const values = [];
return new Promise((resolve, reject) => {
promises.forEach((promise) => {
promise.then(
(value) => {
values.push(value);
if (values.length === promises.length) {
resolve(value);
}
},
(reason) => {
reject(reason);
}
);
});
});
}
}
评论区