
1.promise概念
ES6 原生提供了 Promise 对象。
所谓 Promise,就是一个对象,用来传递异步操作的消息。它代表了某个未来才会知道结果的事件(通常是一个异步操作),并且这个事件提供统一的 API,可供进一步处理。
Promise 对象有以下两个特点。
(1)对象的状态不受外界影响。Promise 对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和 Rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是 Promise 这个名字的由来,它的英语意思就是「承诺」,表示其他手段无法改变。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise 对象的状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为 Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
有了 Promise 对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise 对象提供统一的接口,使得控制异步操作更加容易。
Promise 也有一些缺点。首先,无法取消 Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。第三,当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
var promise = new Promise(function(resolve, reject) {
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
}); promise.then(function(value) {
// success
}, function(value) {
// failure
});
2.举个例子
“小妞妞,嫁给我吧!我发誓,我会对你一辈子好的!”
“这个嘛,你先去问问我爸爸,我大伯以及我大姑的意思,他们全部都认可你,我再考虑考虑!对了,如果我爸没有答复,大伯他们肯定是不会同意的;如果大伯没有答复,大姑也是不会同意的。”
传统思维,基于“去搞定岳父→…等待期…结果来了…→去搞定大伯→…等待期…结果来了…→去搞定大姑→…等待期…结果来了…→去搞定女神→…等待期…结果来了…”的思路,中间是很多的嵌套。
男神.请求({
姓名: "岳父",
成功: 男神.继续请求({
姓名: "大伯",
成功: 男神.继续请求({
姓名: "大姑",
成功: 男神.最终请求({
姓名: "女神",
成功: "求婚成功",
失败: "求婚失败"
}),
失败: 男神.继续请求({
姓名: "大姑",
成功: 男神.最终请求({
姓名: "女神",
成功: "求婚成功",
失败: "求婚失败"
}),
失败: "求婚失败"
})
}),
失败: 男神.继续请求({
姓名: "大伯",
成功: 男神.继续请求({
姓名: "大姑",
成功: 男神.最终请求({
姓名: "女神",
成功: "求婚成功",
失败: "求婚失败"
}),
失败: 男神.继续请求({
姓名: "大姑",
成功: 男神.最终请求({
姓名: "女神",
成功: "求婚成功",
失败: "求婚失败"
}),
失败: "求婚失败"
})
}),
失败: "求婚失败"
})
}),
失败: 男神.请求({
姓名: "岳父",
成功: 男神.继续请求({
姓名: "大伯",
成功: 男神.继续请求({
姓名: "大姑",
成功: 男神.最终请求({
姓名: "女神",
成功: "求婚成功",
失败: "求婚失败"
}),
失败: 男神.继续请求({
姓名: "大姑",
成功: 男神.最终请求({
姓名: "女神",
成功: "求婚成功",
失败: "求婚失败"
}),
失败: "求婚失败"
})
}),
失败: 男神.继续请求({
姓名: "大伯",
成功: 男神.继续请求({
姓名: "大姑",
成功: 男神.最终请求({
姓名: "女神",
成功: "求婚成功",
失败: "求婚失败"
}),
失败: 男神.继续请求({
姓名: "大姑",
成功: 男神.最终请求({
姓名: "女神",
成功: "求婚成功",
失败: "求婚失败"
}),
失败: "求婚失败"
})
}),
失败: "求婚失败"
})
}),
失败: "求婚失败"
})
})
用模拟promise的方式写的函数,但依次执行的触发依然在回调中。我们可能希望得到的代码具有如下与现实世界统一的思维:“搞定岳父→搞定大伯→搞定大姑→搞定女神”,但是,下面的实现却看不出这样的思维。
// 男神的各项参数
var NanShen = {
"身高": 180,
"体重": 80,
"年薪": "200K",
request: function(obj) {
// 成功与否随机决定
// 执行成功的概率为80%
if (Math.random() > 0.2) {
obj.success();
} else {
obj.error();
}
}
}; var Request = function(names, success) {
var index = 0, first = 0;
var request = function() {
if (names[index]) {
NanShen.request({
name: names[index],
success: function() {
first = 0;
console.log("成功拿下" + names[index]);
index++;
request();
},
error: function() {
if (first == 1) {
console.log("依旧没能拿下" + names[index] + ",求婚失败");
return;
} else {
console.log("没能拿下" + names[index] + ",再试一次");
}
first = 1;
request();
}
});
} else {
success();
}
}; request();
}; Request(["岳父", "大伯", "大姑"], function() {
NanShen.request({
name: "女神",
success: function() {
console.log("女神同意,求婚成功!");
},
error: function() {
console.log("女神不同意,求婚失败!");
}
});
})
带有promise写法的代码是如下:
// 男神的各项参数
var NanShen = {
"身高": 180,
"体重": 80,
"年薪": "200K",
request: function(obj) {
// 成功与否随机决定
// 执行成功的概率为80%
if (Math.random() > 0.2) {
obj.success();
} else {
obj.error();
}
}
}; var Request = function(name) {
return new Promise(function(resolve, reject) {
var failed = 0, request = function() {
NanShen.request({
name: name,
success: function() {
console.log(name + "攻略成功!");
failed = 0;
resolve();
},
error: function() {
if (failed == 0) {
console.log("第一次攻略" + name + "失败,重试一次!");
failed = 1;
// 重新攻略一次
request();
} else {
console.log("依然没有拿下" + name + ",求婚失败!");
reject();
}
}
});
}; request();
});
}; Request("岳父") // 搞定岳父,然后...
.then(function() { return Request("大伯"); }) // 搞定大伯,然后...
.then(function() { return Request("大姑"); }) // 搞定大姑,然后...
.then(function() { // 长辈们全部KO后,攻略女神
NanShen.request({
name: "女神",
success: function() {
console.log("女神同意,求婚成功!");
},
error: function() {
console.log("女神不同意,求婚失败!");
}
});
});
通过在函数中合理的设置resolved()和rejected(),然后通过then()单独设置resolved和rejected的具体操作,可以很直观的用同步的方式表示异步的过程