一、名字
promise(首字母小写):一个对象,Promise的实例对象
Promise(首字母大写,单数):Prmoise构造函数
Promises(首字母大写,复数):指代Promise规范
二、Promises/A规范和ES6 Prmoises规范
Prmoises规范有几次升级,目前来说,Promises/A是最新的民间规范。ES6 Prmoises是最新的官方规范。
三、Promises的意义
1、解决回调金字塔的问题(回调圣诞树,回调地狱)
2、可以同时管理成功回调和失败回调
四、所谓“承诺”
Promises这个单词翻译为“承诺”。程序的世界里,理解为:我承诺给你完成这些代码的执行。new有一个Prmoise实例,就是js引擎给你一个承诺。
执行承诺,就会有成功或者失败,只是概率问题。
在程序世界里,一个承诺也只会有三种状态:“未解决(pendding)”、“成功的(resolve)”、“失败的(reject)”。
五、Promise构造函数的能力
本质:prmoises写法的本质就是把 异步写法撸成同步写法。
怎么做到的呢?
就是安排一下代码执行的先后顺序:Promise构造函数有特殊的功能,传入Prmoise构造函数的函数参数会优先第一执行,也就是说,只要new一个Prmoise,那么Promise构造函数的函数参数是最高优先级执行的,一直到new一个Promise对象实例后面的then()代码才会执行。链条行的每一个then()都会等到前面promise有了结果才会执行。
Promise是一个构造函数,用来生成prmoise实例。
Promise构造函数接受一个函数作为参数,这个函数的两个参数分别是:resolve和reject。他们是两个函数,有js引擎提供(自带的。
resolve函数的作用:将promise对象的状态从“未完成”变成“成功”。在异步操作成功时调用,并将异步的结果作为参数传递出去。
reject函数的通:将promise对象的状态从“未完成”变成“失败”。在异步操作失败的时候调用,并将错误作为参数传递出去。
promise对象生成以后,可以用then()方法分别制定resolve状态和reject状态的回到函数
六、撸代码
传统的回调地狱写法:
firstAsync(function(data){
//拿到data的数据 处理业务逻辑 do something
secondAsync(function(data2){
//拿到data2的数据 处理业务逻辑 do something
thirdAsync(function(data3){
//拿到data3的数据 处理业务逻辑 do something
})
})
})
哈哈哈,像不像一个金字塔。可读性和维护性都比较差
引入Promise的写法:
firstAsync().then(function(data){
//拿到data的数据 处理业务逻辑 do something
return secondAsync() //继续处理第二个异步
}).then(function(data2){
//拿到data2的数据 处理业务逻辑 do something
return thirdAsync() //继续处理第二个异步
}).then(function(data3){
//拿到data3的数据 处理业务逻辑 do something
})
通过then的链式写法,把回调按照顺序串联起来。
更直接的例子:有做饭、吃饭、洗碗筷这三个异步的操作,他们是层层依赖,下一步的操作依赖上一步操作的结果
=》
(1)下面通过样例作为演示,我们定义做饭、吃饭、洗碗(cook、eat、wash)这三个方法,它们是层层依赖的关系,下一步的的操作需要使用上一部操作的结果。(这里使用 setTimeout 模拟异步操作)
//做饭
function cook(){
console.log("开始做饭");
var p = new Promise(function(resolve,reject){
setTimeout(function(){
console.log("做饭完毕")
resolve("老北京炸酱面")
},1000)
})
return p;
}
//吃饭
function eat(data){
console.log("开始吃饭:"+data)
var p = new Promise(function(resolve,reject){
setTimeout(function(){
console.log("吃饱啦")
resolve("筷子盘子碗")
},2000)
})
return p
}
//洗碗筷
function wash(data){
console.log("开始洗碗筷:"+data)
var p = new Promise(function(resolve,reject){
setTimeout(function(){
console.log("洗好啦")
resolve("干净的碗筷")
},2000)
})
return p
}
(2)使用 then 链式调用这三个方法:
cook()
.then(function(data){
returneat(data);
})
.then(function(data){
returnwash(data);
})
.then(function(data){
console.log(data);
});
好了,看运行的结果:
Promises.html:14 开始做饭
Promises.html:17 做饭完毕
Promises.html:26 开始吃饭:老北京炸酱面
Promises.html:29 吃饱啦
Promises.html:39 开始洗碗筷:筷子盘子碗
Promises.html:42 洗好啦
Promises.html:54 干净的碗筷
七、all
Promises的all方法,拓展了异步操作的能力,即在所有指定的异步操作都结束后才运行回调。
直接上代码:
//切菜
function cut(){
console.log("开始切菜:青菜")
var p = new Promise(function(resolve,reject){
setTimeout(function(){
console.log("切菜完毕")
resolve("切好的青菜")
},1000)
})
return p
}
//烧水
function boil(){
console.log("开始烧水")
var p = new Promise(function(resolve,reject){
setTimeout(function(){
console.log("烧水完毕")
resolve("烧好的水")
},2000)
})
return p
}
//all then把操作逻辑串起来
Promise.all([cut(),boil()]).then(function(data){
console.log("准备工作完毕")
console.log(data)
})
结果:
开始切菜:青菜
Promises.html:72 开始烧水
Promises.html:64 切菜完毕
Promises.html:76 烧水完毕
Promises.html:84 准备工作完毕
Promises.html:85 ["切好的青菜", "烧好的水"]
八、Promises的race方法:和all类似,是异步能力的拓展,区别是all是所有异步操作都结束才能执行回调, race 的话只要有一个异步操作执行完毕,就立刻执行 then 回调。
注意:其它没有执行完毕的异步操作仍然会继续执行,而不是停止。
上面的切菜烧水操作定义好以后:
Promise.race([cut(),boil()]).then(function(data){
console.log("至少有一个工作准备好了")
console.log(data)
})
结果注意顺序:
开始切菜:青菜
Promises.html:72 开始烧水
Promises.html:64 切菜完毕
Promises.html:89 至少有一个工作准备好了
Promises.html:90 切好的青菜
Promises.html:76 烧水完毕
注意,race的应用场景很多,比如同时向后台发起多个ajax的异步请求,并且都有超时时间设置。
比如:
//请求某个图片资源
function requestImg(){
var p = new Promise(function(resolve, reject){
var img = new Image();
img.onload = function(){
resolve(img);
}
img.src = 'xxxxxx';
});
return p;
}
//延时函数,用于给请求计时
function timeout(){
var p = new Promise(function(resolve, reject){
setTimeout(function(){
reject('图片请求超时');
}, 5000);
});
return p;
}
Promise
.race([requestImg(), timeout()])
.then(function(results){
console.log(results);
})
.catch(function(reason){
console.log(reason);
});
上面代码 requestImg 函数异步请求一张图片,timeout 函数是一个延时 5 秒的异步操作。我们将它们一起放在 race 中赛跑。
如果 5 秒内图片请求成功那么便进入 then 方法,执行正常的流程。
如果 5 秒钟图片还未成功返回,那么则进入 catch,报“图片请求超时”的信息。
网友评论