Promise 最先出现是为了解决编程中的异步行为致使的回调地狱。在没有 Promise 以前,对于函数的异步行为,通常采用回调函数的方式,在一个函数调用结束触发回调函数,这样会致使多层级的回调函数,难以维护。 Promise 有两个参数,一个成功回调,一个失败回调,因此在 Promise 外部,能够准确的得到成功和失败的时机,而且 Promise 支持链式调用,这样能够方便的进行屡次调用,可是永远都是单层级,便于维护。javascript
回调地狱方式html
var sayhello = function (name, callback) {
setTimeout(function () {
console.log(name);
callback();
}, 1000);
}
sayhello("first", function () {
sayhello("second", function () {
sayhello("third", function () {
console.log("end");
});
});
});
//输出: first second third end
复制代码
Promise 写法java
let sayHello = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("first");
resolve();
}, 1000);
});
sayHello
.then(() => {
console.log("second");
})
.then(() => {
console.log("third");
})
.then(() => {
console.log("end");
});
复制代码
咱们能够发现 Promise 无论有多少次逻辑处理,每一次只有一层,清晰可见,不像回调同样,层层嵌套,难以理清。编程
Promise 实例数组
let promise = new Promise(
function(resolve, reject) { // executor(执行者)
setTimeout(()=>{
resolve("done"),1000);
});
复制代码
咱们只须要 new Promise便可建立一个 Promise,建立即马上调用其中的执行者。 executor 接受两个参数:resolve 和 reject 。这些是JavaScript 引擎预约义的,不要咱们建立,咱们只须要在咱们想要告知的状态中调用对应的方法便可。promise
let promise = new Promise(function(resolve, reject) {
resolve("done");
reject(new Error("…")); // 被忽略
setTimeout(() => resolve("…")); // 被忽略
});
复制代码
这儿只能有一个结果或一个 error executor 只能调用一个 resolve
或一个 reject
。任何状态的更改都是最终的。 全部其余的再对 resolve
和 reject
的调用都会被忽略 而且,resolve/reject
只须要一个参数(或不包含任何参数),而且将忽略额外的参数markdown
那么咱们会疑问,咱们费这么大工夫,在 Promise 内部作这么多操做,最后使他产生一个状态是为了什么,他失败与否和咱们以前的回调地狱有什么关系?异步
state 和 result 都是内部的
Promise 对象的 state 和 result 属性都是内部的。
咱们没法直接访问它们。但咱们能够对它们使用 .then/.catch/.finally 方法。
咱们在下面对这些方法进行了描述。
复制代码
上面咱们使用 Promise 生产了一个成功或者失败的结果,能够经过使用 .then
、.catch
和 .finally
方法为消费函数进行结果接收。函数
let promise = new Promise(function(resolve, reject) {
setTimeout(() => resolve("done!"), 1000);
});
// resolve 运行 .then 中的第一个函数
promise.then(
result => alert(result), // 1 秒后显示 "done!"
error => alert(error) // 不运行
);
复制代码
.then
的第一个参数是一个函数,该函数将在 promise resolved 后运行并接收结果。 .then
的第二个参数也是一个函数,该函数将在 promise rejected 后运行并接收 error。 若是咱们只对成功完成的状况感兴趣,那么咱们能够只为 .then
提供一个函数参数:oop
let promise = new Promise(resolve => {
setTimeout(() => resolve("done!"));
}, 1000);
promise.then(alert); // 1 秒后显示 "done!"
复制代码
.catch(f)
调用是 .then(null, f)
的彻底的模拟,它只是一个简写形式。简单说,catch就是一个接收错误结果的方法。 咱们能够对 settled 的 promise 附加处理程序 若是 promise 为 pending 状态,.then/catch/finally
处理程序(handler)将等待它。不然,若是 promise 已是 settled 状态,它们就会运行 自测案例 写一个 3s 后弹窗的 Promise
function delay(ms) {
// 你的代码
return new Promise(resolve,reject){
setTimeout(resolve,3000)
}
}
delay(3000).then(() => alert('runs after 3 seconds'));
复制代码
若是只要失败回调,那么只须要将 then 的第一个参数设置为null, 也可使用 catch ,这里面能够接受 reject 的结果
let promise = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("Whoops!")), 1000);
});
// .catch(f) 与 promise.then(null, f) 同样
promise.catch(alert); // 1 秒后显示 "Error: Whoops!"
复制代码
不管结果如何,最后都会执行这里面的函数。 **finally()**
方法返回一个Promise
。在promise结束时,不管结果是fulfilled或者是rejected,都会执行指定的回调函数。这为在Promise
是否成功完成后都须要执行的代码提供了一种方式。 这避免了一样的语句须要在then()
和catch()
中各写一次的状况。
在我了解完 Promise 后,我对如何实现他很是感兴趣,因而我试着本身来构建一个 Promise。 首先咱们要分析一下咱们的需求,咱们要获得什么,要实现哪些功能,肯定目标。
咱们按照上图,分为两个大步骤,开始进行实现咱们本身的 Promise。
首先构造 Promise 类。
class Promise {
constructor(executor) {
if (typeof executor !== "function") {
console.log("参数不合法");
} else {
this.status = "pending";
this.value = undefined;
this.error = undefined;
//自动运行Promise中的函数
try {
//将resolve和reject函数给使用者
executor(resolve, reject);
} catch (e) {
//若是在函数中抛出异常则将它注入reject中
reject(e);
}
}
}
resolve(data) {
//成功触发
if (this.status === "pending") {
this.status = "fulfilled";
this.value = data;
}
}
reject(data) {
//失败触发
if (this.status === "pending") {
this.status = "rejected";
this.error = data;
}
}
then() {}
catch() {}
finally() {}
}
复制代码
咱们实现了上述几个目标,接下来咱们要实现接受结果信息的方法。
class Promise {
constructor(executor) {
if (typeof executor !== "function") {
console.log("参数不合法");
} else {
this.status = "pending";
this.value = undefined;
this.error = undefined;
//自动运行Promise中的函数
try {
//将resolve和reject函数给使用者
executor(this.resolve, this.reject);
} catch (e) {
//若是在函数中抛出异常则将它注入reject中
this.reject(e);
}
}
}
resolve = (data) => {
//成功触发
if (this.status === "pending") {
this.status = "fulfilled";
this.value = data;
}
};
reject = (data) => {
//失败触发
if (this.status === "pending") {
this.status = "rejected";
this.error = data;
}
};
then(onFulfilled, onRejected) {
if (this.status === "fulfilled") {
onFulfilled(this.value);
}
if (this.status === "rejected") {
onRejected(this.error);
}
}
catch(onRejected) {
if (this.status === "rejected") {
onRejected(this.error);
}
}
finally(onFinally) {
if (this.status !== "pending") {
onFinally();
}
}
}
复制代码
这样,咱们就完成了一个简易版的 Promise。 咱们来将文件引入测试一下,看看结果如何。
<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <script src="./index.js"></script> <script> let promise = new Promise((resolve, reject) => { resolve("coolFish!"); }); promise.then( (data) => { console.log("成功" + data); }, (data) => { console.log("失败" + data); } ); </script> </body> </html>
复制代码
结果和 Promise 同样,能够实现成功和失败的不一样操做,接下来咱们要开始扩展它的功能,从可支持链式调用开始。
首先咱们明确 promise.then(onFulfilled, onRejected ) 作的事情
then(onFulfilled, onRejected) {
//建立并返回一个Promise实例
return new Promise((resolve, reject) => {
let wrapOnFulfilled = () => {
setTimeout(() => {
try {
console.log("wrapOnFulfilled");
let x = onFulfilled(this.value);
resolve(x);
} catch (error) {
reject(error);
}
}, 0);
};
let wrapOnRejected = () => {
setTimeout(() => {
try {
console.log("wrapOnRejected");
let x = onRejected(this.error);
resolve(x);
} catch (error) {
reject(error);
}
}, 0);
};
if (this.status === "fulfilled") {
wrapOnFulfilled();
} else if (this.status === "rejected") {
wrapOnRejected();
} else {
this.onFulfilledCallbacks.push(wrapOnFulfilled);
this.onRejectedCallbacks.push(wrapOnRejected);
}
});
}
复制代码
首先咱们先明确目标 Promise.all
接受一个 promise 数组做为参数(从技术上讲,它能够是任何可迭代的,但一般是一个数组)并返回一个新的 promise。 当全部给定的 promise 都被 settled 时,新的 promise 才会 resolve,而且其结果数组将成为新的 promise 的结果。 咱们来看一张流程图,而后咱们按照流程图来实现咱们的代码
all(promises) {
return new Promise((resolve, reject) => {
// 若是Promise.all接收到的是一个空数组([]),它会当即决议。
if (!promises.length) {
resolve([]);
}
let result = [];
let resolvedPro = 0;
for (let index = 0, length = promises.length; index < length; index++) {
Promise.resolve(promises[index]).then(
(data) => {
// 注意,这里要用index赋值,而不是push。由于要保持返回值和接收到的promise的位置一致性。
result[index] = data;
if (++resolvedPro === length) {
resolve(result);
}
},
(error) => {
reject(error);
}
);
}
});
}
复制代码
// 须要注意的是,若是Promise.race接收到的是一个空数组([]),则会一直挂起,而不是当即决议。
Promise.race = function(promises) {
return new Promise((resolve, reject) => {
promises.forEach((promise) => {
Promise.resolve(promise).then(resolve, reject);
});
});
};
复制代码
// Promise.allSettled 返回一个在全部给定的promise都已经fulfilled或rejected后的promise,
// 并带有一个对象数组,每一个对象表示对应的promise结果。
Promise.allSettled = function(promises) {
return new Promise((resolve, reject) => {
if (!promises.length) {
resolve([]);
}
let result = [];
let resolvedPro = 0;
for (let index = 0, length = promises.length; index < length; index++) {
Promise.resolve(promises[index])
.then((data) => {
// 注意,这里要用index赋值,而不是push。由于要保持返回值和接收到的promise的位置一致性。
result[index] = {
status: FULFILLED_STATE,
value: data,
};
if (++resolvedPro === length) {
resolve(result);
}
})
.catch((error) => {
result[index] = {
status: REJECTED_STATE,
reason: error,
};
if (++resolvedPro === length) {
resolve(result);
}
});
}
});
};
复制代码