共计 4454 个字符,预计需要花费 12 分钟才能阅读完成。
- 为什么须要 Promise
假如我当初有这样一个需要,用户先去登录,登录胜利之后,再去服务端获取用户信息,获取到用户信息之后再去服务端获取前端的动静菜单。个别咱们的 Ajax 申请都是异步模式,为了确保上一步操作胜利再执行下一个申请,所以最终收回的申请伪代码相似上面这样:
$.ajax({
url:'/login',
data:loginForm,
success: function (data) {
// 登录胜利
$.ajax({
url:'/getInfo',
success: function (userInfo) {
// 获取用户信息胜利
$.ajax({
url: '/getMenus',
success: function (menus) {// 获取菜单胜利}
})
}
})
}
})
复制代码
为了确保一个异步工作执行实现后,再执行下一个异步工作,咱们不得不在回调函数中不停的写下去,下面我举的例子是三个申请嵌套,实际上可能会更多。。。这就是前端所谓的回调天堂。而 Promise 就是来解决回调天堂的。
- Promise
Promise 从字面上了解,就是承诺,承诺未来在某一个工夫会做某一件事。通过 Promise 咱们能够将异步工作执行的代码和解决的代码齐全分来到。
还是第一大节这个例子,如果咱们用 Promise 写,那么形式如下:
function login(resolve, reject) {setTimeout(() => {let number = Math.random();
if (number > 0.5) {resolve("login success")
} else {reject("login failed")
}
}, 2000);
}
function getInfo(resolve, reject) {setTimeout(() => {let number = Math.random();
if (number > 0.5) {resolve("getInfo success")
} else {reject("getInfo failed")
}
}, 2000);
}
function getMenus(resolve, reject) {setTimeout(() => {let number = Math.random();
if (number > 0.5) {resolve("getMenus success")
} else {reject("getMenus failed")
}
}, 2000);
}
new Promise(login).then(data => {console.log("login:", data);
return new Promise(getInfo);
}).then(data => {console.log("getInfo:", data);
return new Promise(getMenus);
}).then(data => {console.log("getMenus", data);
}).catch(err => {console.log("err:", err);
})
复制代码
咱们在 Promise 中写异步工作执行的代码,在下面的案例中,松哥通过 setTImeout 办法模仿了一个耗时操作,异步工作执行结束后,咱们调用 resolve 办法返回调用的后果(会进入到下一步的 then 中),也能够调用 reject 办法示意调用失败(会进入到 catch 中)。
- then
then 中的返回值能够分为三种状况。
3.1 失常 return
then 中办法的参数,是上一个 Promise 对象 resolve 的值,一个 Promise 对象能够有多个 then,例如下面案例的登录性能,咱们能够始终 then 上来:
function login(resolve, reject) {setTimeout(() => {let number = Math.random();
if (number > 0.5) {resolve("login success")
} else {reject("login failed")
}
}, 2000);
}
new Promise(login).then(data => {console.log("then1:", data);
return data;
}).then(data => {console.log("then2:", data);
return data;
}).then(data => {console.log("then3:", data);
}).catch(err => {console.log("err:", err);
})
复制代码
这样能够始终返
回,这有点像咱们 Java 中的流式编程。
3.2 抛出异样
在 then 中,咱们能够对返回后果进行判断,不满足条件也能够间接抛出异样,这样就会进入到最近的 catch 代码块中。如下案例:
function login(resolve, reject) {setTimeout(() => {let number = Math.random();
if (number > 0.5) {resolve("login success")
} else {reject("login failed")
}
}, 2000);
}
new Promise(login).then(data => {console.log("then1:", data);
throw new Error("出错啦");
}).then(data => {console.log("then2:", data);
return data;
}).then(data => {console.log("then3:", data);
}).catch(err => {console.log("err:", err);
})
复制代码
像下面这段代码,如果进入到第一个 then 中,第一个 then 间接抛出异样,这样间接就进入到 catch 中了,前面的 then 就都不会执行了。
3.3 返回 Promise
第三种状况就是 then 中也能够返回一个 Promise 对象,这个就如同咱们第二大节的案例,我这里就不再赘述了。
就说一句,如果 then 中返回的是一个 Promise 对象,那么接下来的 then 其实是这个 Promise 对象的 then,而不是一开始的 Promise 的 then 了。例如如下伪代码:
A.then((data)=>{return B}).then(xxx)
复制代码
假如 A 和 B 都是 Promise 对象,那么第二个 then 办法是 B 的 then。
好啦,这就是 then 中的三种返回值状况。
- catch
catch 次要是用来解决异样的状况,两种状况下会进入到 catch 中:
Promise 执行的时候通过 reject 返回数据。
then 中抛出 Error
出了问题,就由最近的 catch 来解决。
- finally
最初还有一个 finally 用来兜底,这一套下来感觉有点像咱们 Java 中的 try-catch-finally,也就是后面无论如何,最终 finally 中的代码都会执行。不过不同于 Java 中的 finally,Promise 中的 finally 在最终执行结束后,还能够持续 then。。。前端的蜜汁操作。 - 其余办法
最初,咱们再来看看 Promise 中的其余静态方法。
6.1 Promise.all()
Promise.all() 办法能够接管多个 Promise 对象,并且只返回一个 Promise 实例,这个办法会等所有输出的 Promise 对象的 resolve 办法都返回的时候,或者所有输出的 Promise 对象中有一个 reject 的时候,这个 all 就会执行完结,来看如下一个案例:
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {setTimeout(resolve, 3000, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {console.log(values);
}).catch(err=>{console.log("err", err);
})
复制代码
当 promise1、promise2 以及 promise3 都执行了 resolve 的时候,就会进入到 then 中,这三个中有任意一个执行了 reject 就会进入到 catch 中。
6.2 Promise.race()
Promise.race() 办法能够接管多个 Promise 对象,一旦迭代器中的某个 Promise resolve 或 reject,返回的 Promise 就会 resolve 或 reject。
和 all 办法的区别在于,race 办法是谁执行的快,就用谁的后果。咱们来看如下一段代码:
const promise1 = new Promise((resolve, reject) => {setTimeout(resolve, 500, 'one');
});
const promise2 = new Promise((resolve, reject) => {setTimeout(reject, 600, 'two');
});
Promise.race([promise1, promise2]).then((value) => {console.log(value);
});
复制代码
promise1 执行工夫短,promise2 执行工夫长,所以最终后果就是 promise1 的后果。
6.3 Promise.reject()
Promise.reject() 办法返回一个带有 reject 起因的 Promise 对象。来看如下一段代码:
function resolved(result) {console.log('Resolved');
}
function rejected(result) {console.error(result);
}
Promise.reject("error").then(resolved).catch(rejected);
复制代码
这个执行的时候就会进入到 catch 中。
6.4 Promise.resolve()
Promise.resolve(value) 办法返回一个以给定值解析后的 Promise 对象。
const promise1 = Promise.resolve(3);
promise1.then(data=>{console.log("data", data);
},err=>{console.log("err", err);
})
复制代码
这个用法比较简单,还有一些其余办法我就不一一列举了。
源码附件曾经打包好上传到百度云了,大家自行下载即可~
链接: https://pan.baidu.com/s/14G-b…
提取码: yu27
百度云链接不稳固,随时可能会生效,大家放松保留哈。
如果百度云链接生效了的话,请留言通知我,我看到后会及时更新~
开源地址
码云地址:
https://gitee.com/ZhongBangKe…
Github 地址:
https://gitee.com/ZhongBangKe…