对于没有见过的东西,人们会排斥,因为内心会恐惧。 —— 题记
对于JavaScript
这门语言来说,带P
开头的关键词总是给人一种莫名的恐惧感。在初学JavaScript
时,对ProtoType
和 __proto__
非常恐惧,因为初级应用里根本用不到这两位,但是面试官却总喜欢问这类的问题。后来随着工作经验积累,看问题和编程的层面提升后,觉得其实也很简单。而我对今天的主人公promise
也是这样的,从起初的抵触、害怕,到后来的从容相处。其实对编程语言来说,新的东西不会是横空出世的,它的诞生一定是为了解决现有的某个问题,一种未知的必然。
promise
的理解promise
单词的中文释义虽然是 “允许、许诺”,但我们不能用字面的意思去认知它,而是应该把它理解为 “先知” 。另外重要的一点是,promise
是一种形式,不要把它看成是某些方法、函数之类的。
JavaScript
是单线程的,也就是一条线下来的,这是代码世界的一条规则,而人当下所经历的现实世界中,很多行为结果是未知的,不是即时呈现的。这i就类似于JavaScript
中发送一个Ajax
请求,不同的返回值造成不同的影响。promise
则扮演了一个”先知”的角色。预先将你的未来告知,规划好你继续的路。你无需等待最终的结果出来,继续现在的生活。
如果你是一个先知,你是没有等待、异步这种感觉的。这就是promise
的作用,一种先知的形式,好比上帝,已经在他的时间维度一瞬间规划好你的一生。而对于JavaScript
代码而言,我们就是上帝,我们能够预先知道代码的方向,并规划了代码的人生。典型的就是React
组件的生命周期:
import React, { Component } from 'react'
class myComponent extend Component {
constructor() {
console.log('组件初始化');
}
componentWillMount() {
console.log('组件将开始构建');
}
render() {
console.log('组件渲染中');
}
componentDidMount() {
console.log('组件完成构建');
}
componentWillUnmount() {
console.log('组件将开始销毁');
}
componentDidUnmount() {
console.log('组件完成销毁');
}
}
export default myComponent
这里顺带延伸一下React组件的完整的生命周期:
getDefaultProps()
作用于组件类,只调用一次,返回对象用于设置默认的props
,对于引用值,会在实例中共享。
getInitialState()
作用于组件的实例,在实例创建时调用一次,用于初始化每个实例的state
,此时可以访问this.props
。
componentWillMount()
在完成首次渲染之前调用,此时仍可以修改组件的state
。
render()
必选的方法,创建虚拟DOM,该方法具有特殊的规则:
this.props
和this.state
访问数据null
、false
或任何React
组件componentDidMount()
真实的DOM被渲染出来后调用,在该方法中可通过this.getDOMNode()
访问到真实的DOM元素。此时已可以使用其他类库来操作这个DOM。注意:在服务端中,该方法不会被调用。
componentWillReceiveProps()
组件接收到新的props时调用,并将其作为参数nextProps使用,此时可以更改组件props及state。
componentWillReceiveProps: function(nextProps) {
if (nextProps.bool) {
this.setState({
bool: true
});
}
}
shouldComponentUpdate()
组件是否应当渲染新的props或state,返回false表示跳过后续的生命周期方法,通常不需要使用以避免出现bug。在出现应用的瓶颈时,可通过该方法进行适当的优化。在首次渲染期间或者调用了forceUpdate方法后,该方法不会被调用
componentWillUpdate()
接收到新的props或者state后,进行渲染之前调用,此时不允许更新props或state。
componentDidUpdate()
完成渲染新的props或者state后调用,此时可以访问到新的DOM元素。
componentWillUnmount()
组件被移除之前被调用,可以用于做一些清理工作,在componentDidMount方法中添加的所有任务都需要在该方法中撤销,比如创建的定时器或添加的事件监听器。
在现实世界中大部分的操作都是非即时呈现的,如果用JavaScript
表示我们的一生,那就会是一个超级无限长的嵌套。
我们写代码的时候是以上帝的身份来处理代码的,我们是造物主,而不是以代码中的角色身份。目前的JavaScript
异步回调就是按代码的视角——随着时间推移,代码中的人和物会经历不同的过程。但如果使用了promise
,我们可以把异步操作转换成更符合先知视角的形式来展现。
下面介绍一个 非常形象的 “男神求婚”的promise
实现例子,来自 张鑫旭《ES6 JavaScript Promise的感性认知》:
具体的思路是:
/**
* @desc 男神求婚promise示例
**/
var NanShen = {
"身高": 180,
"体重": 80,
"年薪": 200000,
request: function(obj) {
// 成功与否随机决定,执行成功的概率为80%
if (Math.random() > 0.2) {
obj.success();
} else {
obj.error();
}
}
};
var Request = function(names, success) {
var index = 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] + ",求婚失败");
} else {
console.log("没能拿下" + names[index] + ",再试一次");
}
first = 1;
request();
}
});
} else {
success();
}
};
request();
};
Request(['岳父', '大伯', '大姑'], function() {
NanShen.request({
name: "女神",
success: function() {
console.log("女神同意,求婚成功!");
},
error: function() {
console.log("女神不同意,求婚失败!");
}
});
});
然后会随机产生不同的结果:
@参考:张鑫旭《ES6 JavaScript Promise的感性认知》