深入理解JavaScript的Promise - Go语言中文社区

深入理解JavaScript的Promise


写在前面

对于没有见过的东西,人们会排斥,因为内心会恐惧。 —— 题记

对于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组件的完整的生命周期:

React组件生命周期

getDefaultProps()

作用于组件类,只调用一次,返回对象用于设置默认的props,对于引用值,会在实例中共享。

getInitialState()

作用于组件的实例,在实例创建时调用一次,用于初始化每个实例的state,此时可以访问this.props

componentWillMount()

在完成首次渲染之前调用,此时仍可以修改组件的state

render()

必选的方法,创建虚拟DOM,该方法具有特殊的规则:

  • 只能通过this.propsthis.state访问数据
  • 可以返回nullfalse或任何React组件
  • 只能出现一个顶级组件(不能返回数组)
  • 不能改变组件的状态
  • 不能修改DOM的输出

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的感性认知》

具体的思路是:

  1. 买些好烟好酒登门拜访岳父大人,恳请岳父大人把女儿许配给自己;1日后,得到岳父答复,如果同意,攻略大伯;如果不同意,继续攻略1次,要是还不行,失败告终;
  2. 同上攻略大伯;
  3. 买上等化妆品,然后同上攻略大姑;
  4. 拿着满满的offer拿下女神。
/**
 * @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的感性认知》

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/u011413061/article/details/51816128
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-05-29 23:18:16
  • 阅读 ( 1002 )
  • 分类:Go深入理解

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢