Promise
Promise 是什么?
词语本意:
发音:[ˈprɒmɪs]
词性:名词,
翻译:许诺,允诺。
MDN解释
- Promise 对象用于一个异步操作。
- 一个Promise表示一个现在,将来或永不可能可用的值。
按照书写方式来解释
可以将异步操作的书写方式变成一种队列化的书写方式,并按照我们写的那样的预期来执行返回符合预期的结果。
为什么需要Promise
js为检查表单而生,其首要目标是操作dom,界面冻结会造成非常不友好的用户体验,所以dom操作大多是异步的。
注意:同步操作的处理器未执行完成会使得界面无法响应用户的其他操作,而异步操作则可以避免该问题。
常见的异步操作语法:
1. 异步事件
$('#start').on('click',startHandler);
function startHandler(){} // 定义事件响应的处理器函数
用户点击start元素就会触发一个异步事件去执行,再次触发不必等待前一次事件执行完成,就可以再次触发。
2. 回调函数
$.ajax('http://baidu.com',{
success:function(res){
// 成功回调处理器
},
error:function(e){
// 失败回调处理器
}
});
用户发送一个向百度服务器获取数据的异步请求
3. 无阻塞高并发的node的诞生
更加严重的依赖异步操作才能完成无阻赛高并发的特性。
然而异步回调这种方式并不是理想的,它却有一些问题,
比如:
- 回调地狱这种难于维护的书写方式。
更深层次的问题:
- 嵌套回调中的循环语句出错后,无法正常的使用return和throw终止
- 无法正常检索堆栈信息(每一个回调都会重新建立堆栈)
- 多个回调之间难以建立联系
Promise详解
一个promise的基本使用案例:
new Promise(
// 执行器 executor
function ( resolve, reject ) {
//一段耗时很长的异步操作
resolve(); //异步处理成功
reject(); // 异步处理失败
//注意:resolve和reject这俩个回调函数被调用是互斥的
}
).then( function A(){
//成功,下一步
},
function B(){
//失败,做善后处理
}
);
- promise是一个代理对象,它和原先要进行的操作并无关系。
- 它通过引入一个回调,避免更多的回调。
promise有三个状态:
pending 初始状态 fulfilled 操作成功 rejectd 操作失败
- promise一经创建,执行器便会立刻执行;
- 异步操作通过调用resolve改变promise状态为fulfilled,通过调用reject改变promise状态为rejected;
- promise状态发生改变就会触发then里面的响应函数;
- promise状态一经改变,不会再变。
promise最简单的实现:
//范例1
console.log('here we go');
new Promise( resolve => {
setTimeout( () => {
resolve('hello');
}, 2000);
}).then( value => {
console.log( value + ' world');
});
/* 控制台日志 */
here we go
// 2s以后
hello world
// 范例2
console.log('here we go');
new Promise(resolve => {
setTimeout( () => {
resolve('hello');
}, 2000);
}).then(value => {
console.log(value);
return new Promise( resolve => {
setTimeout(() => {
resolve('world');
}, 2000);
});
}).then(value => {
console.log( value + ' world');
});
/* 控制台日志 */
here we go
// 2s后
hello
// 2s后
world world
// 假如一个Promise已经完成了,再.then()会怎样?
console.log('start');
let promise = new Promise(resolve => {
setTimeout(() => {
console.log('the promise fulfilled');
resolve('hello, world');
}, 1000);
});
setTimeout(() => {
promise.then( value => {
console.log(value);
});
}, 3000);
/* 控制台 */
17:37:29.015 start
17:37:30.016 the promise fulfilled
17:37:32.017 hello, world
// 假如在.then()的函数里面不返回新的Promise,会怎样?
console.log('here we go');
new Promise(resolve => {
setTimeout( () => {
resolve('hello');
}, 2000);
}).then( value => {
console.log(value);
console.log('everyone');
(function () {
return new Promise(resolve => {
setTimeout(() => {
console.log('Mr.Laurence');
resolve('Merry Xmas');
}, 2000);
});
}());
// return false;
}).then( value => {
console.log(value + ' world'); return 0
}).then( value => {
console.log(value + ' world');
}).then( value => {
console.log(value + ' world');
});
/* 控制台 */
17:53:03.175 here we go
17:53:03.191 Promise {<pending>}
17:53:05.181 hello
17:53:05.181 everyone
17:53:05.181 undefined world
17:53:05.182 0 world
17:53:05.182 undefined world
17:53:07.187 Mr.Laurence
从日志可以看出,
1. 执行器中必须回调resolve或者reject改变promise的状态;
2. 当状态改变后继续调用then方法,但是promise中的状态已经无法改变了;
3. 可以看到promise对象帮我们生成了一个队列,这个队列一直存在。
then方法
- then() 接受俩个状态响应函数参数,分别代表fulfilled和rejected
- then() 返回一个新的Promise实例,所以它可以链式调用
- 状态响应函数可以返回新的Promise,其他值,或者不返回值
- 如果返回新的Promise,那么下一级.then()会在新的promise状态改变之后执行
- 如果返回其它任何值,则会立刻执行下一级.then()
- then里面有then的情况
1). 因为.then()返回的还是Promise实例。
2). 会等里面的.then()执行完,在执行外面的。
3). 对我们来说,此时最好将其展开,会更好阅读。
测试
问题:下面四种Promise的区别是什么?
前提:doSomething方法和doSomethingElse方法均返回一个promise实例。
// #1
doSomething().then(function() {
return doSomethingElse();
});
// #2
doSomething().then(function(){
doSomethingElse();
});
// #3
doSomething().then(doSomethingElse());
// #4
doSomething().then(doSomethingElse);
// 解析:
// #1
doSomething().then(function() {
return doSomethingElse();
});
//符合预期的,可以继续回调then方法获取doSomethingElse的结果
// #2
doSomething().then(function(){
doSomethingElse();
});
//then中没有返回promise,所以之后的then无法获取到doSomethingElse的结果,并且与doSomethingElse几乎同时执行
// #3
doSomething().then(doSomethingElse());
// then应该接收一个状态处理函数,当前这种情况传入了一个promise实例,无法获取上层promise的结果,而该层then会被忽略,下一层会获取到doSomething()的结果
// #4
doSomething().then(doSomethingElse);
// then方法中吧doSomethingElse直接当成状态处理函数也是可以达到预期的
错误处理 catch方法
catch和then一样会返回一个promise实例。如果没有抛出错误,该实例默认也会返回fulfilled状态。
Promise 常用函数
promise.all
接收一个数组参数,返回一个新的promise实例,响应函数中的结果为数组中的每个promise的结果。
与map连用
使用forEach和reduce实现队列
ES2017 的async/await
该学习笔记是学习慕课网中 Promise入门 记录
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。