js中的promise是一个异步编程的解决方案,语法层面上他是一个构造函数,名字为Promise()。
Promise正如字面意思-承诺,“承诺将来会执行”约定的事情。我们首先需要了解Promise的三种状态:
Promise构造函数接收一个函数作为参数,该函数的两个参数分别是resolve和reject。resolve和reject是两个函数,由JavaScript引擎提供,不用自己部署。
//resolve, reject名称不能修改
const promise = new Promise(function(resolve, reject) {
// ...some code
if ( /*异步操作成功,执行resolve方法,目的一般是将某些结果返回出去*/ ) {
resolve(value);
} else {
/*异步操作失败,执行reject方法,目的一般也是将某些结果返回出去*/
reject(error);
}
});
Promise 实例生成以后,可以用then方法分别指定resolved状态和rejected 状态的回调函数。也就是对返回的任务结果进行处理。then方法可以接受两个回调函数作为参数。其中,第二个函数是可选的,不一定要提供。
promise.then(resolved = function(value) {
// success,对返回的结果value进行处理
},
rejected = function(error) {
//failure,直接把错误类型报给用户
});
一般来说,不要在then方法里面定义 Reject 状态的回调函数(即then的第二个参数),最好使用catch方法。
// bad
promise
.then(function(data) {
// success
}, function(err) {
// error
});
// good
promise
.then(function(data) { //cb
// success
})
.catch(function(err) {
// error
});
finally方法用于指定不管前面Promise对象状态如何,都会执行的操作。
promise .then(result => {···})
.catch(error => {···})
.finally(()=> {···})
上面代码中,不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数。
finally方法的回调函数不接受任何参数,它与Promise对象状态无关,不依赖于 Promise 的执行结果。
promise.all()该方法用于将多个Promise实例,包装成一个新的Promise实例。
传一个promise的数组,当所有的promise都完成(resolved),回调所有成功的结果, 如果有一个回调执行失败,then是不会执行的,则在catch回调第一个失败的结果
几个异步操作是强相关的,后续步骤必须依赖这几个步骤全部成功才能进行
promise.all将多个promise放在一起处理,能简化回调的处理(不然需要调很多次,不科学),一个then回调就能拿到所有数据,对其进行处理,也能用一个catch回调捕获所有的异常
var p = Promise.all([p1,p2,p3]);
代码如下(执行成功示例):
getPromise(a) {
return new Promise((resolve, reject) => {
if (a > 0) {
console.log(a);
resolve("execute in p" + a + ".then");
} else {
reject("error in p" + a, error);
}
})
},
testPromise(){
console.log("test")
const p1 = this.getPromise(1);
const p2 = this.getPromise(2);
const p3 = this.getPromise(3);
const promiseArr = [p1,p2,p3];
Promise.all(promiseArr).then((results) => {
console.log('success:', results)
}).catch(e => { // 失败的时候则返回最先被reject失败状态的值
console.log("error", e)
})
}
只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
代码如下(执行失败示例1):
getPromise(a) {
return new Promise((resolve, reject) => {
if (a > 0) {
console.log(a);
resolve("execute in p" + a + ".then");
} else {
reject("error in p" + a + ".error");
}
})
},
testPromise(){
console.log("test")
const p1 = this.getPromise(1);
const p2 = this.getPromise(-2);
const p3 = this.getPromise(3);
const promiseArr = [p1,p2,p3];
Promise.all(promiseArr).then((results) => {
console.log('success:', results)
}).catch((error) => { // 失败的时候则返回最先被reject失败状态的值
console.log("error", error)
})
}
执行结果 : error error in p-2.error
代码如下(执行失败示例2):
getPromise(a) {
return new Promise((resolve, reject) => {
if (a > 0) {
console.log(a);
resolve("execute in p" + a + ".then");
} else {
reject("error in p" + a + ".error");
}
})
},
testPromise(){
console.log("test")
const p1 = this.getPromise(1);
const p2 = this.getPromise(-2);
const p3 = this.getPromise(-3);
const promiseArr = [p1,p2,p3];
Promise.all(promiseArr).then((results) => {
console.log('success:', results)
}).catch((error) => { // 失败的时候则返回最先被reject失败状态的值
console.log("error", error)
})
}
执行结果 : error error in p-2.error
只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
Promise.all()
这里尝试了案例,但是自己的测试结果很迷惑,应该是测试的方式不对
以下案例是网上找的别的进行测试
案例参考来源
test_promise_Promise_all
// 辅助方法 makePromise 用来生成 Promise
makePromise(name, delay) {
return new Promise((resolve) => {
console.log(`${name} started`);
setTimeout(() => {
console.log(`${name} completed`);
resolve(name);
}, delay);
});
},
test_promise_Promise_all(){
const app = this;
// 下面的 data 变量是演示用的数据,代表 setTimeout 的延时。
const data = [2000, 1, 1000];
Promise.all(data.map((v, k) => app.makePromise(k, v))).then(res => {
console.log(res);
});
},
执行结果
Promise.all 方法,会等所有 Promise 执行完毕后,把结果放在数组里,注意这里 Promise 的执行不存在什么顺序还是并发问题,因为 Promise 本身就代表一个已经执行的过程,所以 Promise.all 就是在等所有过程结束
0 started App.vue:46
1 started App.vue:46
2 started App.vue:46
1 completed App.vue:48
2 completed App.vue:48
0 completed App.vue:48
Array(3) [ 0, 1, 2 ]
test_promise_reduce
// 辅助方法 makePromise 用来生成 Promise
makePromise(name, delay) {
return new Promise((resolve) => {
console.log(`${name} started`);
setTimeout(() => {
console.log(`${name} completed`);
resolve(name);
}, delay);
});
},
test_promise_reduce(){
// 首先加入 bluebird 的 Promise 对象
const Promise = require('bluebird'); // 这里的 bluebird 好像是一个第三方的库
const app = this;
// 下面的 data 变量是演示用的数据,代表 setTimeout 的延时。
const data = [2000, 1, 1000];
Promise.reduce(data,(total, v, k) => {
return app.makePromise(k, v).then(res => {
return total + res;
});
}, 0).then(res => {
console.log(res);
})
}
执行结果
Promise.reduce 方法是一个顺序执行 Promise 的方法,所谓顺序执行,其实就是从左到右按顺序去创建 Promise ,并且始终只有一个 Promise 在运行。看 bluebird 的 源码 ,可以发现,一些顺序执行的方法,比如 Promise.mapSeries 和 Promise.each ,都是基于 Promise.reduce 来实现的,这里的 reduce 和 Array.reduce 一样,测试代码:
0 started App.vue:46
0 completed App.vue:48
1 started App.vue:46
1 completed App.vue:48
2 started App.vue:46
2 completed App.vue:48
3
但是自己在测试的时候发现好像不太对啊??
以下为不完整测试,自己给自己绕晕了
test_promise_Promise_all
getPromise(a) {
return new Promise((resolve, reject) => {
if (a > 0) {
let d = new Date()
console.log(a + "start----" + d.getSeconds() + ":" + d.getMilliseconds());
setTimeout(() => {
console.log(a + "end----" + d.getSeconds() + ":" + d.getMilliseconds());
resolve("execute in p" + a + ".then");
}, a * 100)
} else {
reject("error in p" + a + ".error");
}
})
},
test_promise_Promise_all() {
const p1 = this.getPromise(1);
const p3 = this.getPromise(3);
const p2 = this.getPromise(2);
const p4 = this.getPromise(4);
const p5 = this.getPromise(5);
const promiseArr = [p1, p2, p3, p4, p5];
Promise.all(promiseArr).then((results) => {
console.log('success:', results)
}).catch((error) => { // 失败的时候则返回最先被reject失败状态的值
console.log('error:', error)
})
},
}
getPromise(a) {
return new Promise((resolve, reject) => {
if (a > 0) {
let d = new Date()
console.log(a + "start----" + d.getSeconds() + ":" + d.getMilliseconds());
setTimeout(() => {
console.log(a + "end----" + d.getSeconds() + ":" + d.getMilliseconds());
resolve("execute in p" + a + ".then");
}, a * 100)
} else {
reject("error in p" + a + ".error");
}
})
},
test_promise_reduce() {
const p1 = this.getPromise(1);
const p3 = this.getPromise(3);
const p2 = this.getPromise(2);
const p4 = this.getPromise(4);
const p5 = this.getPromise(5);
const promiseArr = [p1, p2, p3, p4, p5];
let doTask = promiseArr.reduce((prev, next) => prev.then(() => next), Promise.resolve());
doTask.then(result => {
console.log('success:', result)
}).catch(error => {
console.log("error", error)
});
}
执行结果
1start----42:660
3start----42:661
2start----42:661
4start----42:661
5start----42:661
1end----42:660
2end----42:661
3end----42:661
4end----42:661
5end----42:661
success: execute in p5.then
重新测试:好像和 newPromise 没关系,好像是 newPromise 的方式不对,new 的时候好像就执行了,所以上面测不出来
makePromise(a, delay) {
return new Promise((resolve, reject) => {
if (a >= 0) {
let d = new Date()
console.log(a + "start----" + d.getSeconds() + ":" + d.getMilliseconds());
setTimeout(() => {
console.log(a + "end----" + d.getSeconds() + ":" + d.getMilliseconds());
resolve("execute in p" + a + ".then");
}, delay)
} else {
reject("error in p" + a + ".error");
}
})
},
test_promise_Promise_all(){
const app = this;
const data = [2000, 1, 1000];
Promise.all(data.map((v, k) => app.makePromise(k, v))).then(res => {
console.log(res);
});
},
test_promise_reduce(){
const Promise = require('bluebird');
const app = this;
const data = [2000, 1, 1000];
Promise.reduce(data,(total, v, k) => {
return app.makePromise(k, v).then(res => {
return total + res;
});
}, 0).then(res => {
console.log(res);
})
}