在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
多快好省!前端后端,线上线下,名师精讲
更多了解 加: