1、简单的promise使用
let p = new Promise(function (resolve, reject) {
console.log("start");
resolve("成功的回调");
// reject("失败的回调");
});
p.then((data) => {
console.log("success---"+data);
}, (err) => {
console.log("error---"+err);
});
console.log("end" );
执行上面的代码,输出为:
start
end
success---成功的回调
由此可见:
- 1)我们在new一个Promise时,需要传递一个excutor执行器(函数),会立即被调用,这个执行器接收两个参数,分别为resolve和reject方法;调用resolve方法表示成功,调用reject方法表示失败;
- 2)同时返回的promise实例,会有一个then方法,then方法中传递两个参数,分别是成功的回调和失败的回调函数
除上述之外,我们还应了解Promise状态:
- promise实例一共具有三种状态
- 异步操作未完成(pending)
- 异步操作成功(fulfilled)
- 异步操作失败(rejected)
- 其中这三种状态的变化途径只有两种:
- 异步操作成功,从“未完成”到“成功”,即状态由pending变为fulfilled;
- 异步操作失败,从“未完成”到“失败”,即状态由pending变为rejected;
代码如下:
class Promise {
constructor(fn){
this.data = undefined; // 回调成功的data
this.error = undefined; // 失败回调的error
this.status = "pending";
// 下面在fn中传入resolve和reject方法时,需要进行this绑定,否则在resolve和reject方法中获取到的this为undefined
fn(this.resolve.bind(this), this.reject.bind(this));
}
resolve(data){
if (this.status === "pending") {
// 重置状态为fulfilled,并置this.data为获取的数据
this.status = "fulfilled";
this.data = data;
}
}
reject(error){
// 重置状态为rejected,并置this.error为错误信息
if (this.status === "pending") {
this.status = "rejected";
this.error = error;
}
}
then(onfulfilled,onrejected){
// 当状态为fulfilled时,执行成功的回调
if(this.status === "fulfilled"){
onfulfilled(this.data);
}
// 当状态为rejected时,执行成功的回调
if (this.status === "rejected"){
onrejected(this.error);
}
}
}
module.exports = Promise;
2、promise的异步处理
- 我们知道,promise的主要作用是用于处理异步函数,在以往的异步中,比如我们有一个ajax请求中传递参数,但是这个参数来源于另一个ajax的返回值,那么就会有了如下代码:
$.ajax({
url:url1,
success:function (data) {
$.ajax({
url:url2,
data:data,
success:function () {
}
})
}
});
-
如果一层嵌套还好,但如果出现多层,代码就会看起来很庞大,就产生了回调地狱,如果使用promise的话,代码就会看起来整齐很多。下面我们首先实现promise中异步处理。
-
如下代码,如果使用官网的Promise,会有如下输出:
let Promise = require("./promise");
let p = new Promise(function (resolve, reject) {
console.log("start");
setTimeout(() => {
resolve("成功的回调");
},1000)
// reject("失败的回调");
});
p.then((data) => {
console.log("success---"+data);
}, (err) => {
console.log("error---"+err);
});
console.log("end" );
输出结果如下:
start
end
success---成功的回调 // 1s后输出
-
但是如果使用上面我们写的promise,会发现,只有
start和end
输出,这是由于:1)promise中excutor执行完之后,由于异步那么resolve函数还未执行
2)此时就会执行promise实例上的then方法,此时promise的status状态为pending状态,自然也不会执行onfulfilled与onrejected方法
3)待1s过后,执行resolve方法,将status的状态置为fulfilled状态,程序运行结束
-
为了解决上面的问题,我们可以在then方法中,如果此时处于pending状态,可以将onfulfilled与onrejected方法存放于一个数组中,在执行到resolve或者reject方法时,再执行then中传递的方法,
-
之所以放于数组中,是由于对于同一个promise实例,then方法可以被多次调用;如果只保存当前函数,那么执行多个then方法时,不能保证所有then方法中的onfulfilled或onrejected都被执行到
-
代码如下:
class Promise {
constructor(fn){
this.data = undefined; // 回调成功的data
this.error = undefined; // 失败回调的error
this.status = "pending";
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
// 下面在fn中传入resolve和reject方法时,需要进行this绑定,否则在resolve和reject方法中获取到的this为undefined
fn(this.resolve.bind(this), this.reject.bind(this));
}
resolve(data){
if (this.status === "pending") {
// 重置状态为fulfilled,并置this.data为获取的数据
this.status = "fulfilled";
this.data = data;
this.onResolvedCallbacks.forEach(fn => {
fn();
})
}
}
reject(error){
// 重置状态为rejected,并置this.error为错误信息
if (this.status === "pending") {
this.status = "rejected";
this.error = error;
this.onRejectedCallbacks.forEach(fn => {
fn();
})
}
}
then(onfulfilled,onrejected){
// 当状态为fulfilled时,执行成功的回调
if(this.status === "fulfilled"){
onfulfilled(this.data);
}
// 当状态为rejected时,执行成功的回调
if (this.status === "rejected"){
onrejected(this.error);
}
// 当状态为pending时,那么将onfulfilled与onrejected方法进行存储,在执行resolve或者reject时进行执行
if(this.status === "pending"){
// 这里push onfulfilled 与 onrejected 方法时,不直接push,而是push一个函数,在函数中执行onfulfilled 与 onrejected是为了获取resolve或者reject函数中传递的data或者error
this.onResolvedCallbacks.push(() => {
onfulfilled(this.data);
});
this.onRejectedCallbacks.push(() => {
onrejected(this.error);
});
}
}
}
module.exports = Promise;