Promise 对象用于表示一个异步操作的最终完成 (或失败), 及其结果值.
我的理解:Promise使得异步的写法不像之前那样一直回调,而可以用同步的代码书写格式去写异步代码。
以一个实例开头:以下实例,产生一个随机数,比0.5大触发Promise的resolve方法,比0.5小触发Promise的reject方法。prom对象通过then方法捕获resolve和reject,通过resolve或reject触发prom.then方法中的对应的处理函数。从而实现异步事件的代码同步的写法。
let prom = new Promise(function(resolve, reject){
let num = Math.random() - 0.5;
setTimeout(() => {
if(num > 0){
resolve(num);
}else{
reject(num);
}
}, 5000);
})
console.log(prom);
console.log(prom.then(function(value){
console.log("status is resolved");
return "value is resolve"
},function(value){
console.log("status is rejected");
return "value is reject"
}))
(1)构造函数Promise创建对象,得到的是一个Promise对象,该对象可以通过then方法来捕获resolve和reject,而返回一个新的Promise对象。
(2)new Promise的方式创建Promise对象,传入的处理函数是立即执行函数,且接收两个参数,分别是resolve和reject,resolve()执行,表明Promise对象达到完成且成功的状态,reject()执行表明Promise对象达到完成且失败的状态。
(3)resolve()和reject()两个方法可以接收参数,并将参数传给对应的then方法对应的处理函数。
(4)Promise对象包括两个值,状态:PromiseStatus、传递的值:PromiseValue。
(1)pending状态下,无返回值
得到Promise {
所有Promise对象在then执行前都是
1)new Promise等待then的执行前
let prom1 = new Promise(function(resolve, reject){
$.get("https://www.easy-mock.com/mock/5b4c4032189fc57b63eb8410/example/getMovie", function(res){
if(res){
resolve(res);
}else{
reject("error")
}
})
})
console.log(prom1);
prom1.then(function(data){
console.log(data);
},function(error){
console.log(error)
})
2)Promise.resolve().then()
console.log(Promise.resolve().then())
3)Promise.reject().then()
console.log(Promise.reject().then())
4)Promise.all([]).then()
console.log(Promise.all([]).then())
6)Promise.race([]).then()
console.log(Promise.race([]).then())
原因:Promise是微任务,console.log是宏任务,在执行console的时候,Promise还未执行呢,当然是pending状态。
(2)resolved状态(fulfilled状态)
resolved状态是当Promise对象达到resolve()执行的条件时,返回的Promise对象的状态会改为resolved。与此同时对应的then方法捕获到状态的改变,执行then的处理函数。
let prom = new Promise(function(resolve, reject){
let num = Math.random() - 0.5;
setTimeout(() => {
if(num > 0){
resolve(num);
}else{
reject(num);
}
}, 5000);
})
console.log(prom); Promise {}
setTimeout(() => {
console.log(prom); Promise {: 0.3569827867211466}
}, 6000);
1)那么我们在立即执行函数中,立即触发resolve()或reject(),打印出来的Promise对象也是完成的状态,
打印结果:Promise {
console.log(new Promise(function(resolve, rejected){
resolve("success")
}))
2)我们直接调用Promise的resolve方法,也会得到resolved的状态:
console.log(Promise.resolve("success")) Promise {: "success"}
特别注意:resolve()方法传入的值,即使当前Promise对象的返回值,也是传给then方法的数据。
Promise.resolve() 和 Promise.reject()方法是宏任务一样的执行,返回完成状态的Promise对象
(3)rejected状态
失败的时候的状态,和resolved状态都是完成状态。
then方法捕获Promise状态完成,值来自Promise对象。
(1)then的执行时机(执行顺序)
let prom1 = new Promise(function(resolve, reject){
$.get("https://www.easy-mock.com/mock/5b4c4032189fc57b63eb8410/example/getMovie", function(res){
if(res){
resolve(res);
console.log(111);
}else{
reject("error")
}
})
})
prom1.then(function(data){
console.log(data);
},function(error){
console.log(error)
})
创建Promise对象的resolve()和reject()处理函数也是微任务。 上面代码111先执行
(2)链式调用的原理
Prom对象的PromiseValue会传递给调用的then方法,then方法处理函数return返回的结果,作为新Promise对象的PromiseValue值传递给下一个then方法。
执行顺序,两处的then对比,222比success先执行,为什么?
let prom1 = new Promise(function(resolve, reject){
$.get("https://www.easy-mock.com/mock/5b4c4032189fc57b63eb8410/example/getMovie", function(res){
if(res){
resolve(res);
console.log(111);
Promise.resolve("222").then(val => console.log(val))
}else{
reject("error")
}
})
})
prom1.then(function(data){
console.log(data);
return "success";
},function(error){
console.log(error)
return "faild";
}).then(success => console.log(success),faild => console.log(faild));
(3)值的传递
(4)catch方法关系
catch方法捕获Promise对象的reject状态;catch() 方法返回一个Promise,并且处理拒绝的情况。它的行为与调用Promise.prototype.then(undefined, onRejected)
相同。事实上, calling obj.catch(onRejected)
内部calls obj.then(undefined, onRejected)
下面实例中,捕获prom1的reject
let prom1 = new Promise(function(resolve, reject){
$.get("https://www.easy-mock.com/mock/5b4c4032189fc57b63eb8410/example/getMovie", function(res){
if(res){
reject(res);
}
})
})
prom1.catch(val => console.log(val))
let prom1 = new Promise(function(resolve, reject){
$.get("https://www.easy-mock.com/mock/5b4c4032189fc57b63eb8410/example/getMovie", function(res){
if(res){
reject(res);
}
})
})
prom1.then(function(data){
console.log(data);
},function(error){
console.log(error);//捕获reject()
})
Promise.reject("faild").catch(val => console.log(val))
(5)finally方法关系
不管是then方法、catch方法、还是finally方法,都是捕获调用它的Promise对象。
then
返回的 Promise 将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值。有返回值——>带有该值的接收状态then
返回的 Promise 将会成为接受状态,并且该接受状态的回调函数的参数值为 undefined
。无返回值——> 值为undefined的接收状态then
返回的 Promise 将会成为拒绝状态,并且将抛出的错误作为拒绝状态的回调函数的参数值。错误——> 值为错误原因的拒绝状态then
返回的 Promise 也会成为接受状态,并且将那个 Promise 的接受状态的回调函数的参数值作为该被返回的Promise的接受状态回调函数的参数值。接收状态的Promise ——> 值为该Promise的值 接收状态then
返回的 Promise 也会成为拒绝状态,并且将那个 Promise 的拒绝状态的回调函数的参数值作为该被返回的Promise的拒绝状态回调函数的参数值。拒绝状态的Promise ——> 值为该Promise的值的拒绝状态pending
)的 Promise,那么 then
返回 Promise 的状态也是未定的,并且它的终态与那个 Promise 的终态相同;同时,它变为终态时调用的回调函数参数与那个 Promise 变为终态时的回调函数的参数是相同的。pending状态的Promise ——> (1)catch() 方法返回一个Promise,并且处理拒绝的情况。它的行为与调用Promise.prototype.then(undefined, onRejected)
相同。 (事实上, calling obj.catch(onRejected)
内部calls obj.then(undefined, onRejected)
).
返回一个Promise对象,所以可以链式调用。
所以我们在处理reject的时候,需要在后面跟catch方法:
Promise.reject("fail").catch(function(value){
console.log(value);
})
(2)finally()
方法返回一个Promise
。在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数。这为在Promise
是否成功完成后都需要执行的代码提供了一种方式。
这避免了同样的语句需要在then()
和catch()
中各写一次的情况。
由于无法知道promise
的最终状态,所以finally
的回调函数中不接收任何参数,它仅用于无论最终结果如何都要执行的情况。
注意一个关于throw的关键字:抛出异常错误
throw new TypeError("Oops, we haven't got JSON!");
throw new Error("11");
throw Error("22")
Promise.all(iterable)
方法返回一个 Promise
实例,此实例在 iterable
参数内所有的 promise
都“resolved”或参数中不包含 promise
时回调完成;
如果参数中 promise
有一个失败(rejected),此实例回调失败(reject),失败的原因是第一个失败 promise
的结果。
如果传入的iteratable对象内不包含Promise,也是返回一个Promise对象:
Promise.all([1,2,3])
Promise执行完成后的值:
它通常在启动多个异步任务并发运行并为其结果创建承诺之后使用,以便人们可以等待所有任务完成。
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);
});
上面代码3秒后打印:[3, 42, "foo"]
特别注意:
(1)上面实例中Promise.all的用法,同时setTimeout的使用。
(2)返回值将会按照参数内的 promise
顺序排列,而不是由调用 promise
的完成顺序决定。
比如调整上面几个的排列顺序:
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 3000, 'foo');
});
Promise.all([promise3,promise1, promise2]).then((values) => {
console.log(values);
});
打印结果:["foo", 3, 42]
下面实例中,当两个Promise对象都resolve时,返回一个数组,长度为2,内容为两个resolve传递的值
let prom1 = new Promise(function(resolve, reject){
$.get("https://www.easy-mock.com/mock/5b4c4032189fc57b63eb8410/example/getMovie", function(res){
if(res){
resolve(res);
}else{
reject("prom1 reject");
}
})
})
let prom2 = new Promise(function(resolve, reject){
$.get("https://www.easy-mock.com/mock/5b4c4032189fc57b63eb8410/example/restful/:id/list", function(res){
if(res){
resolve(res);
}else{
reject("prom2 reject");
}
})
})
Promise.all([prom1, prom2]).then(val => console.log(val))
问:为什么打印的是数组?
答:因为Promise.all接收的是一个数组,每个数组的promise执行的结果,返回到对应promise的位置上。所以当每个Promise执行完成后,all的参数就是["foo", 3, 42] ,此时调用then方法,将其打印出来。
Promise.race(iterable)
方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。竞争关系,一旦有一个Promise执行结束,就返回它的执行完成状态,其他的Promise对象不再执行。
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 200, 'one');
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'two');
});
Promise.race([promise1, promise2]).then((value) => {
console.log(value); two
// Both resolve, but promise2 is faster
});
如果传的迭代是空的,则返回的 promise 将永远等待。
如果传入的参数数组包含一个或多个非承诺值和/或已解决/拒绝的承诺,则 Promise.race
将解析为参数数组中找到的第一个值。
传入非Promise对象或已解决或已拒绝的Promise对象:
var resolvedPromisesArray = [Promise.resolve(33), Promise.resolve(44)];
var p = Promise.race(resolvedPromisesArray);
console.log(p); //Promise {}
setTimeout(function(){
console.log('the stack is now empty'); //the stack is now empty
console.log(p); //Promise {: 33}
});
传入值为Promise对象的iterator对象:比如值为Promise的数组
var p1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 500, "one");
});
var p2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, "two");
});
Promise.race([p1, p2]).then(function(value) {
console.log(value); // "two"
// 两个都完成,但 p2 更快
});
var p3 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, "three");
});
var p4 = new Promise(function(resolve, reject) {
setTimeout(reject, 500, "four");
});
Promise.race([p3, p4]).then(function(value) {
console.log(value); // "three"
// p3 更快,所以它完成了
}, function(reason) {
// 未被调用
});
var p5 = new Promise(function(resolve, reject) {
setTimeout(resolve, 500, "five");
});
var p6 = new Promise(function(resolve, reject) {
setTimeout(reject, 100, "six");
});
Promise.race([p5, p6]).then(function(value) {
// 未被调用
}, function(reason) {
console.log(reason); // "six"
// p6 更快,所以它失败了
});
正常的使用,传递多个异步任务,当其中一个任务结束,返回该任务的处理结果
let prom1 = new Promise(function(resolve, reject){
$.get("https://www.easy-mock.com/mock/5b4c4032189fc57b63eb8410/example/getMovie", function(res){
if(res){
resolve(res);
}else{
reject("prom1 reject");
}
})
})
let prom2 = new Promise(function(resolve, reject){
$.get("https://www.easy-mock.com/mock/5b4c4032189fc57b63eb8410/example/restful/:id/list", function(res){
if(res){
resolve(res);
}else{
reject("prom2 reject");
}
})
})
Promise.race([prom1, prom2]).then(val => console.log(val))
结果:其中一个任务的resolve()值,或reject()值