共计 4502 个字符,预计需要花费 12 分钟才能阅读完成。
Promise 从字面上了解,就是承诺,承诺未来在某一个工夫会做某一件事。通过 Promise 咱们能够将异步工作执行的代码和解决的代码齐全分来到。
小伙伴们晓得,松哥最近在录 TienChin 我的项目,用的 RuoYi-Vue 脚手架,前端对于网络申请的中央,很多都波及到了 Promise,为了让小伙伴们能更好的了解前端代码,咱们抽空整一篇文章和大家聊聊整个 Promise。
- 为什么须要 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 中)。
3. 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 中的三种返回值状况。
4. catch
catch 次要是用来解决异样的状况,两种状况下会进入到 catch 中:
- Promise 执行的时候通过 reject 返回数据。
- then 中抛出 Error
出了问题,就由最近的 catch 来解决。
5. finally
最初还有一个 finally 用来兜底,这一套下来感觉有点像咱们 Java 中的 try-catch-finally,也就是后面无论如何,最终 finally 中的代码都会执行。不过不同于 Java 中的 finally,Promise 中的 finally 在最终执行结束后,还能够持续 then。。。前端的蜜汁操作。
6. 其余办法
最初,咱们再来看看 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);
})
这个用法比较简单,没啥好说的。
还有一些其余办法我就不一一列举了,感兴趣的小伙伴们能够看看 MDN 上的相干解说:https://developer.mozilla.org…。
好啦,这个货色搞懂了,咱们再去看 TienChin 我的项目的前端,就会非常容易了!