这是我参与11月更文挑战的第七天,活动详情请查看:2021最后一次更文挑战
1.含义
promise 是异步编程的一种解决方案,promise对象是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果,从他获取异步操作的消息。
1)promise 对象的特点:
- 对象的状态不受外界的影响。promise 对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功) 和 rejected(已失败);
- 一旦状态改变,就不会再改变,任何时候都可以得到这个结果;
2)缺点:
- 无法取消promise,一旦新建他就会立即执行,无法中途取消
- 如果不设置回调函数,promise内部抛出的错误,不会反应到外部
- 当处于pending状态时,无法得知目前的状态是刚刚开始还是即将完成
2.基本用法
promise对象是一个构造函数,用来生成promise实例。
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
// 理解:promise构造函数接受俩个参数,分别是resolve 和reject。
promise.then(function(value) {
// success
}, function(error) {
// failure
});
// promise 实例生成后,可以使用then 方法 分别指定 resolved状态 和reject 状态的回调函数。
1)promise 新建后就会立即执行
let promise = new Promise(function (resolve,reject) {
console.log("1,promise");
resolve();
})
promise.then(function () {
console.log('3,resolved.')
})
console.log("2,hello")
// promise 新建之后立即就会执行---所以就会立即执行 输出 1,promise
// then 方法指定的回调函数,将在当前脚本所有任务同步执行完成之后才会执行----输出 在 2 hello 之前按照顺序执行 和 1,hello
// 当当前脚本执行完毕之后,then里的内容才会执行 ---- 输出 3,resolved
2) 调用 resolve或者reject 并不会终结 promise 的参数函数的执行。
new Promise((resolve, reject) => {
resolve(1);
return resolve(1); // 加上这行话 就不会在输出2
console.log(2);
}).then(r => {
console.log(r);
});
// 因为立即 resolved 的Promise 是在本轮事件循环的末尾执行,总是晚于本轮事件循环的同步任务。所以先输出2后输出1的内容
更好的写法:
new Promise((resolve, reject) => {
return resolve(1);
}).then(r => {
console.log(2);
console.log(r);
});
输出的结果
//2
//1
3. Promise.prototype.then()
then方法是定义在原型对象Promise.prototype上的,为Promise 实例添加状态改变时的回调函数。
then方法返回一个新的promise实例,注意不是原来的Promise实例
getJSON("/post/1.json").then(function(post) {
return getJSON(post.commentURL);
}).then(function (comments) {
console.log("resolved: ", comments);
}, function (err){
console.log("rejected: ", err);
});
// 等价写成箭头函数的写法
getJSON("/post/1.json").then(
post => getJSON(post.commentURL)
).then(
comments => console.log("resolved: ", comments),
err => console.log("rejected: ", err)
);
4.Promise.prototype.catch()
1、含义
Promise.prototype.catch()方法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数。
catch 捕获promise 抛出的异常的状态rejected或者是then 方法指定的回调函数在运行中抛出的错误,也会被catch方法捕获。
const promise = new Promise(function(resolve, reject) {
throw new Error('test');
});
promise.catch(function(error) {
console.log(error);
});
// Error: test
// 写法一
const promise = new Promise(function(resolve, reject) {
try {
throw new Error('test');
} catch(e) {
reject(e);
}
});
promise.catch(function(error) {
console.log(error);
});
// 写法二
const promise = new Promise(function(resolve, reject) {
reject(new Error('test'));
});
promise.catch(function(error) {
console.log(error);
});
2、catch 返回一个promise对象,同时还可以继续调用then方法
const someAsyncThing = function () {
return new Promise(function (resolve,reject) {
// 因为 x 没有被声明定义,所以会报错
// let x = 5; // 如果声明了,则不会报错
resolve(x +2);
})
}
//调用someAsyncThing
someAsyncThing().catch(function (error) {
console.log('no no no',error)
}).then(function () {
console.log('carry on');
})
// 因为 x 没有被声明定义,所以会报错 在运行完catch()方法指定的回调函数之后,会接着
// 运行后面的then()方法指定的回调函数。如果没有报错,则会跳过catch()方法。
5.promise.prototype.finally()
1、含义
- finally()方法用于指定不管promise 对象最后的状态 如何,都会执行的操作。
- finally 方法的回调函数不接受任何参数,所以finally方法里面的操作和promise 返回的状态无关,不依赖于promise的执行结果。
2、finally 本质是then方法的特例。
promise
.finally(() => {
// 语句
});
// 等同于
promise
.then(
result => {
// 语句
return result;
},
error => {
// 语句
throw error;
}
);
// 说明:如果不使用finally方法,同样的语句需要为成功和失败俩种情况各写一次。有了finally方法,则只需要写一次。
6.promise.all()
1.含义
promise.all() 方法用于将多个Promise 实例,包装成一个新的实例。
const p = Promise.all([p1, p2, p3]);
promise.all() 方法接受一个数组作为参数,p1、p2、p3 都是他的实例。如果参数不是数组的话,但必须有iterator 的接口,且返回的每一个成员都是promise 实例。
p的状态由p1、p2、p3决定,分成两种情况。
(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
const p1 = new Promise((resolve, reject) => {
resolve('hello');
})
.then(result => result)
.catch(e => e);
const p2 = new Promise((resolve, reject) => {
throw new Error('报错了');
})
.then(result => result)
.catch(e => e);
Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// ["hello", Error: 报错了] ---- 这是rejected 输出的语句
// Array(2) 0:hello 1:Error: 报错了 --- 这是resolv的执行结果
说明:上面代码中,p1会resolved,p2首先会rejected,但是p2有自己的catch方法,该方法返回的是一个新的 Promise 实例,p2指向的实际上是这个实例。该实例执行完catch方法后,也会变成resolved,导致Promise.all()方法参数里面的两个实例都会resolved,因此会调用then方法指定的回调函数,而不会调用catch方法指定的回调函数。
7.总结
- all() :是数组中的所有的对象变为resolve 只要有一个状态变为reject 则执行 all() 方法里的内容。
- race():只要有一个实例发生改变时,P的总数组的状态就会随之改变。
- allSettled():只有等待这些参数的实例都返回的结果,不管是fulfilled 还是rejected,包装实例才会结束。
- any():只要参数所有的实例都变成fulfilled状态,包装的实例就会变成rejected 状态。如果所有的参数实例都变成rejected状态。包装实例就会变成rejected状态。
8.promise.resolve()
需要将现有的对象转为promise 对象,promise.resolve() 方法就起到这个作用。
1、参数是一个Promise 实例
如果参数是一个promise实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。
2、参数是一个thenable 对象
thenable对象指的是具有then方法的对象。
let thenable = {
then: function(resolve, reject) {
resolve(42);
}
};
let p1 = Promise.resolve(thenable);
p1.then(function (value) {
console.log(value); // 42
});
// 总结:promise.resolve()方法会将这个对象转为promise 对象,然后立即执行thenable 对象的then 方法
// thenable 对象的then()方法执行后,对象P1状态就变为resolved。从而立即执行最后那个then方法指定的回调函数
// 最后输出的结果为42
3、参数不是具有then方法的对象,或者根本就不是对象
const p = Promise.resolve('Hello'); // 字符串对象不具有then() 方法
p.then(function (s) {
console.log(s)
});
// Hello
如果参数是一个原始值,或者是一个不具有then() 方法的对象,则Promise.resolve()方法返回一个新的Promise对象(从一生成的状态就是resolved,所以回调函数会立即执行),状态为resolved。
4、不带有任何参数
注:立即resolve()的promise 对象,是在本轮事件循环的结束时执行,而不是在下一轮的事件循环的开始时执行。
setTimeout(function () {
console.log('three');
}, 0);
Promise.resolve().then(function () {
console.log('two');
});
console.log('one');
// one
// two
// three
setTimeout(fn, 0)在下一轮“事件循环”开始时执行,Promise.resolve()在本轮“事件循环”结束时执行,console.log('one')则是立即执行,因此最先输出。
最后
文章到此为止了,如果有不足之处,欢迎大家评论指出。
附件
附上代码的连接地址,帮助初学的小伙伴有一个更深的认识,打开控制台就可以看到输出结果。 项目代码地址