在JavaScript中,异步通常就伴随着回调(复习:异步和回调)。
为什么呢?看下面的代码:
let result = false;
function loadSuccess() {
setTimeout(function () {
result = true;
}, 1000)
}
loadSuccess();
console.log(result ? 'oh yeah!' : 'what happen?');
@想一想@:结果是什么?(演示:并在控制台看一下result的值)
但我们希望的,或者说更符合合理预期的结果应该是:result的值在loadSuccess()中被改变,然后再影响console.log()。
@想一想@:能不能由某个异步方法返回bool值?
var result = loadSuccess();这是不行的,只能把上述代码改成这个样子:
function loadSuccess(callback) {
setTimeout(function () {
//如果这个result也依赖于另一个异步函数,咋整?
var result = true;
console.log(result ? 'oh yeah!' : 'what happen?');
}, 1000)
}
但是,假设console.log()也要异步执行,而且其返回值/改变的值也要供另一个异步方法使用(事实上很容易出现这种情况,尤其是node.js中),代码会演变成什么样子?
function loadSuccess(callback) {
setTimeout(function () { //获得result值的异步方法
let result = true;
setTimeout(function () {
let words = result ? 'oh yeah!' : 'what happen?';
setTimeout(function () {
console.log(words);
},10)
}, 10)
}, 10)
}
这就是大名鼎鼎的回调地狱(callback hell):
之所以称其为“地狱”,是因为:
promise是ES6推出的新的内置类。使用它的大致方式是:
let p = new Promise(function (resolve) {
resolve('resolve');
});
p.then(function (value) {
console.log(value);
});
console.log('after then');
注意:Promise的构造函数的参数是一个函数,而且函数的参数resolve还是函数
@想一想@:这个参数是不是必须名为resolve?
断点演示:
我们得到的规律是:
但这有什么作用呢?
用Promise重写之前地狱回调代码:
let p = new Promise(function (resolve) {
setTimeout(function () {
var result = true;
resolve(result); //先获得result的值
}, 1000);
});
p.then(function (result) {
console.log(result ? 'oh yeah!' : 'what happen?'); //一定会在得到result的值后才运行
})
这样,代码的可读性是不是变得更强了?
有了Promise,我们把可以把loadSuccess封装成:
function loadSuccess(resolve, reject) {
setTimeout(function () {
var result = true;
resolve(result); //先获得result的值
}, 10);
}
loadSuccess()就可以不用改了,它通过resolve()向外部提供了result,外部要想获得其值,只需要拿到相应的Promise对象:
let p = new Promise(loadSuccess);然后继续调用p.then()就OK了。
Promise()中的回调函数不是总能成功执行,当这种情况出现时,应该将其反馈给外界。于是:
每一个Promise实例中都保存着一个状态(status)。状态值有三种:
注意:这三种状态在Promise实例外部无法改变,只能在Promise的构造函数中的代码实现。
方法then()总是会在Promise实例化之后,检查其状态:
除了then(),promise对象还有两个方法:
let p = new Promise(function (resolve, reject) {
setTimeout(function () {
var result = true;
if (true) {
throw new Error('......');
resolve(result);
} else {
reject('error');
}
console.log('after error');
}, 1000);
});
p.then(function (result) {
console.log(result ? 'oh yeah!' : 'what happen?');
}).catch(function (reason) { //推荐:可读性更高
console.log(reason);
}).finally(function () {
console.log('finally');
})
因为then()还会返回一个新的Promise实例,所以then()后面还可以紧接着继续调用then()……(复习:JQuery的链式调用)
需要return
new Promise((resolve, reject) => {
setTimeout(function() {
console.log('第 1 次resolve');
resolve(false);
}, 500)
}).then(function(result) {
return new Promise((resolve, reject) => {
setTimeout(function() {
console.log('第 2 次resolve');
resolve(result);
}, 500)
});
}).then(function(result) {
if (result) {
console.log('oh yeah!');
} else {
console.log('what happen?')
}
})
此外,把error装进reject中,就可以轻松catch:
try {
throw Error('heng!');
} catch (e) {
reject(e);
}
其他参考:MDN
多快好省!前端后端,线上线下,名师精讲
更多了解 加: