1.什么是promise
JavaScript中的 promise 与现实生活中的承诺非常相似。首先让我们看看现实生活中的承诺。
promise 词典中的定义:保证某人会做某事或某件事会发生。
那么当有人向你承诺时,会发生什么呢?
由此我们可以看出Promise是ES6中新增的一种异步编程的方式,用于解决回调的方式的各种问题,提供了更多的可能性。
2.promise的状态
Promise对象一共有3中状态,pending,fullfilled(又称为resolved)和rejected: - pending——任务仍在进行中。 - resolved——任务已完成。等同于兑现承诺 - reject——任务出错。无法兑现承诺
Promise对象初始时处于pending状态,其生命周期内只可能发生以下一种状态转换: - 任务完成,状态由pending转换为resolved。 - 任务出错返回,状态由pending转换为rejected。
Promise对象的状态转换一旦发生,就不可再次更改。这或许就是Promise之“承诺”的含义吧。
使用 Promise 的优点:
使用 Promise 的缺点: - 无法取消 Promise,一旦新建它就会立即执行,无法中途取消。 - 如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。 - 当处于 pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
3.promise基本用法
1)创建Promise
let p = new Promise(executor(resolve, reject));
Promise 构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve 和 reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。
Promise 新建后立即执行,then 方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,catch 同理。
例如:
<script>
let flag = true;
let fn = function () {
return new Promise((resolve, reject) => {
if (flag) {
resolve('成功');
} else {
reject('失败');
}
});
}
promise = fn();
promise.then((resp) => {
console.log('in the then function....');
})
console.log("输出promise对象=>");
console.log(promise);
</script>
运行结果:
输出promise对象=>
Promise {<fulfilled>: "成功"}
in the then function....
说明先输出的promise对象再执行了then方法。
比如,男朋友以前承诺情人节给女朋友,送礼物。当然这仅仅是个承诺,能否兑现谁也不清楚。可以用promise来描述这个故事。
<script>
let keepWord;
keepWord = true;
promise = new Promise(function(resolve, reject) {
if (keepWord) {
resolve("男朋友信守承诺给女朋友送iphone11");
} else {
reject("男朋友存款不够,无法兑现承诺!");
}
});
console.log(promise);
</script>
运行结果:
Promise {<resolved>: "男朋友信守承诺给女朋友送iphone11"}
2)then Promise对象创建完成之后,我们需要调用then(succ_handler, fail_handler)方法指定成功和/或失败的回调处理。 例如:
<script>
let keepWord;
keepWord = false;
promise = new Promise(function(resolve, reject) {
if (keepWord) {
resolve("男朋友信守承诺给女朋友送iphone11");
} else {
reject("男朋友存款不够,无法兑现承诺!");
}
});
promise.then(function(resolve){
console.log(JSON.stringify(resolve)+",亲男朋友一口!");
},function(reject){
console.log(JSON.stringify(reject)+",罚跪搓衣板!");
})
console.log(promise);
</script>
运行结果:
Promise {<rejected>: "男朋友存款不够,无法兑现承诺!"}
"男朋友存款不够,无妨兑现承诺!",罚跪搓衣板!
这就是最基本的使用Promise编写异步处理的方式了。但是,有几点需要注意: (1)then方法可以只传入成功或失败回调。 (2)executor函数是立即执行的,而成功或失败的回调函数会到当前EventLoop的最后再执行。下面的代码可以验证这一点: (3)then方法返回的是一个新的Promise对象,所以可以链式调用。 例如:
<script>
let keepWord;
keepWord = true;
promise = new Promise(function(resolve, reject) {
if (keepWord) {
resolve("男朋友信守承诺给女朋友送iphone11");
} else {
reject("男朋友存款不够,无法兑现承诺!");
}
});
promise.then(function(resolve){
console.log(JSON.stringify(resolve)+",亲男朋友一口!");
return resolve;
},function(reject){
console.log(JSON.stringify(reject)+",罚跪搓衣板!");
}).then(function(resolve){
console.log(JSON.stringify(resolve)+",亲男朋友第二口!");
})
console.log(promise);
</script>
运行结果:
Promise {<resolved>: "男朋友信守承诺给女朋友送iphone11"}
"男朋友信守承诺给女朋友送iphone11",亲男朋友一口!
"男朋友信守承诺给女朋友送iphone11",亲男朋友第二口!
(4)Promise对象的then方法可以被调用多次,而且可以被重复调用。 例如:
<script>
let keepWord;
keepWord = true;
promise = new Promise(function(resolve, reject) {
if (keepWord) {
resolve("男朋友信守承诺给女朋友送iphone11");
} else {
reject("男朋友存款不够,无法兑现承诺!");
}
});
promise.then(function(resolve){
console.log(JSON.stringify(resolve)+",亲男朋友一口!");
},function(reject){
console.log(JSON.stringify(reject)+",罚跪搓衣板!");
});
promise.then(function(resolve){
console.log(JSON.stringify(resolve)+",亲男朋友第二口!");
},function(reject){
console.log(JSON.stringify(reject)+",罚跪搓衣板!");
});
promise.then(function(resolve){
console.log(JSON.stringify(resolve)+",亲男朋友第三口!");
},function(reject){
console.log(JSON.stringify(reject)+",罚跪搓衣板!");
});
console.log(promise);
</script>
运行结果:
Promise {<resolved>: "男朋友信守承诺给女朋友送iphone11"}
"男朋友信守承诺给女朋友送iphone11",亲男朋友一口!
"男朋友信守承诺给女朋友送iphone11",亲男朋友第二口!
"男朋友信守承诺给女朋友送iphone11",亲男朋友第三口!
3)catch 由前面的介绍,我们知道,可以由then方法指定错误处理。但是ES6提供了一个更好用的方法catch。直观上理解可以认为catch(handler)等同于then(null, handler)。
<script>
let keepWord;
keepWord = false;
promise = new Promise(function(resolve, reject) {
if (keepWord) {
resolve("男朋友信守承诺给女朋友送iphone11");
} else {
reject("男朋友失踪...");
}
});
promise.then(function(resolve){
console.log(JSON.stringify(resolve)+",亲男朋友一口!");
return resolve;
}).catch(function(err){
console.log("出现异常:"+JSON.stringify(err));
})
console.log(promise);
</script>
运行结果:
Promise {<rejected>: "男朋友失踪..."}
出现异常:"男朋友失踪..."
4)finally finally表示在执行完then 或 catch 指定的回调函数以后,都会执行finally方法指定的回调函数。 例如:
<script>
let keepWord;
keepWord = false;
promise = new Promise(function(resolve, reject) {
if (keepWord) {
resolve("男朋友信守承诺给女朋友送iphone11");
} else {
reject("男朋友失踪...");
return new Error("男朋友失踪...");
}
});
promise.then(function(resolve){
console.log(JSON.stringify(resolve)+",亲男朋友一口!");
return resolve;
}).catch(function(err){
console.log("出现异常:"+JSON.stringify(err));
}).finally(function(){
console.log('无论是否有男朋友,都要对自己好一些...');
})
console.log(promise);
</script>
运行结果:
Promise {<rejected>: "男朋友失踪..."}
出现异常:"男朋友失踪..."
无论是否有男朋友,都要对自己好一些...
4.实际案例
下面给出一个promise结合AJAX的一个案例。
<script>
let getJSON = function (url) {
return new Promise(function (resolve, reject) {
let xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onreadystatechange = function () {
if (xhr.readyState !== 4) {
return;
}
if (xhr.status === 200) {
resolve(xhr.response);
} else {
reject(new Error(xhr.statusText));
}
}
xhr.send();
});
}
getJSON("http://api.icndb.com/jokes/random")
.then(function (responseText) {
return JSON.parse(responseText);
})
.then(function (obj) {
console.log(obj.value.joke);
})
.catch(function (err) {
console.log(err.message);
});
</script>
getJSON函数接受一个url地址,请求json数据。但是请求到的数据是文本格式,所以在第一个then方法的回调中使用JSON.parse将其转为对象,第二个then方法回调再进行具体处理。
5.深入理解then then方法遵循以下原则: - then方法提供一个供自定义的回调函数,若传入非函数,则会忽略当前then方法。 - 回调函数中会把上一个then中返回的值当做参数值供当前then方法调用。 - then方法执行完毕后需要返回一个新的值给下一个then调用(没有返回值默认使用undefined)。 - 每个then只可能使用前一个then的返回值。
以下实例:
<script>
let func = function() {
return new Promise((resolve, reject) => {
resolve('成功');
});
};
let foo = function() {
console.log('一定要执行foo方法...');
return 'foo';
}
func().then(function () {
return foo();
}).then(resp => {
console.warn(resp);
console.warn('1 =========>');
});
func().then(function () {
foo();
}).then(resp => {
console.warn(resp);
console.warn('2 =========>');
});
func().then(foo()).then(resp => {
console.warn(resp);
console.warn('3 =========>');
});
func().then(foo).then(resp => {
console.warn(resp);
console.warn('4 =========>');
});
</script>
运行结果:
一定要执行foo方法...
一定要执行foo方法...
一定要执行foo方法...
一定要执行foo方法...
foo
1 =========>
undefined
2 =========>
成功
3 =========>
foo
4 =========>
小结 Promise是ES6新增的一种异步编程的解决方案,使用它可以编写更优雅,更易读,更易维护的程序。Promise已经应用在各个角落了,个人认为掌握它是一个合格的Javascript开发者的基本功。