javascript学习笔记-Promise的基本用法

javascript学习笔记-Promise的基本用法

javascript,这门语言我接触好久了,但对它的了解一直是:用它写的代码我都看的懂,但真写起来就很别扭,要是扣细节就更不懂了。为什么呢?一方面这类动态语言在ide上的语法提示很弱,比不了java这种静态语言,没了提示就像屠夫没了刀,废了一半!另一方面毕竟不是主力语言,用到的地方能cv别人的代码绝不自己瞎折腾。最近在看一个nodejs写的开源项目,实现的功能挺有意思的,类似自动化工作流的东西,我一直对这方面的东西感兴趣,所以关注了,看了下有些细节看不明白,因此准备好好学习下JavaScript。

期约(Promise)这个概念很抽象,简单说是为优化异步编程而生,本文也主要研究这个东西。

js的异步编程

js写的程序一般都是单线程跑的,如果没有异步的机制,所有逻辑都通过同步方式就会有很多问题,直观体现就是浏览器一直转圈圈卡着,基于这一点,js中大量用到异步编程。

js中用异步编程的方式一般是这样的:

function useAsyncDemo() {
    console.log('11111111111')
    setTimeout(() => {
        console.log('22222222222')
    }, 0)
    console.log('333333333333')
}
// --------输出-------
//11111111111
//333333333333
//22222222222

js的执行引擎维护一个任务队列,在某个时机分配异步任务执行

js的回调函数

写过js代码的一般都知道回调函数这个概念,从字面意思就可以看出是:函数在某个时机将会被回调

至于什么时机,我的理解是一般是某个异步任务执行完成后再调用这个函数。有了这种设计,即可实现直到异步函数执行结束再执行某个函数逻辑这种效果。

举个例子:

// 回调函数的例子
// 有了回调函数,实现了直到异步返回结果后再执行回调函数的效果
function useCallBackDemo() {
    function cb(res) {
        console.log('我是一个回调函数,我接收并打印一个参数:', res);
    }

    setTimeout(() => {
        let res = 100;
        console.log('异步计算了2s得到一个结果:', res);
        console.log('调用回调函数开始:', cb);
        cb(res);
    }, 2000);
}
// 输出
//异步计算了2s得到一个结果: 100
//调用回调函数开始: [Function: cb]
//我是一个回调函数,我接收并打印一个参数: 100

get请求的实现一般是通过异步的方式,然后搭配回调函数可获得请求的结果。有一种场景是需要嵌套调用get请求的,如:

  1. 请求用户信息
  2. 基于1的用户id请求账户信息
  3. 基于2的账户信息请求余额信息

要实现这种效果如果是基于回调函数的方式,不可避免地会形成回调嵌套,嵌套层数一多将形成回调地狱

如:

// 什么是回调地狱
// 体现在层层嵌套
function cbHellDemo() {
    // 模拟get操作,get操作一般耗时,异步执行
    // 接收一个回调函数的参数
    function get(cb) {
        setTimeout(() => {
            let res = Math.round(Math.random() * 10);
            console.log('1s后从服务端响应的数据:', res);
            cb(res);
        }, 1000)
    }
    get((res) => {
        console.log('我是cb1,我获得的结果是:', res);
        console.log('cb1还需继续发送get请求!');
        get((res) => {
            console.log('我是cb2,我获得的结果是:', res);
            console.log('cb2还需继续发送get请求!');
            get((res) => {
                console.log('我是cb3,我获得的结果是:', res);
            })
        })
    })
}

使用Promise优化异步编程

我对Promise的基本理解是优化异步编程,先看Promise类型的基本用法:

// Promise能够优化回调的操作
// 先看看Promise的基本特性
// 输出为1111->2222->3333
// 说明Promise构造的执行器函数会被同步执行
function basicPromiseDemo1() {
    console.log('111111111111')
    let p1 = new Promise(resolve => {
        console.log('2222222222222')
        resolve();
    })
    console.log('3333333333333')
}

// 输出为111111 33333333333 2222222222
// Promise的执行器函数逻辑运行到resolve时,期约会落定
// 落定后的期约会触发兑付或拒绝事件,体现在then方法中定义的相关事件被调用
// 从结果看出即使resolve先于最后的console.log('333333')执行,其事件的触发逻辑还是较靠后执行
// 原因是事件触发的执行逻辑是异步的
function basicPromiseDemo2() {
    let p1 = new Promise(resolve => {
        console.log('1111111111');
        resolve('22222222222');
    });
    p1.then(value => {
        console.log(value);
    })
    console.log('33333333333333')
}

从上面的例子可以看出Promise的then方法中定义的兑付或拒绝事件会在期约落定(resolve)后被异步执行,且能够很容易的将值传递到后续事件中,如:resolve('22222222222'),将‘2222222222’传递到后续事件的入参中。这个特性简直是拯救回调地狱的绝佳方法!

// 通过Promise很优雅实现:等到异步计算结果返回后再执行后续逻辑 这件事。
function basicPromiseDemo3() {
    new Promise(resolve => {
        setTimeout(() => {
            let res = 100;
            console.log('异步计算了1s得到一个结果:', res);
            resolve(res);
        }, 1000)
    }).then(value => {
        console.log('从异步计算结束后接收到的值为:', value);
    })
}

只要将异步操作包裹在Promise的执行器中,并在恰当时机resolve即可。

解决回调地狱的方式:

// 使用Promise解决回调地狱的问题!
// 形式上体现为链式调用,无论是阅读还是编写都友好了很多
// 一定程度上可以理解为异步转同步
function basicPromiseDemo4() {
    function get() {
        return new Promise(resolve => {
            setTimeout(() => {
                let res = Math.round(Math.random() * 10);
                console.log('1s后从服务端响应的数据:', res);
                resolve(res);
            }, 1000);
        })
    }
	// then方法执行返回的值必然是Promise对象,如果返回的是普通的值,如'Ok'则直接是落定状态,但如果事件中显势的返回Promise对象则以返回的Promise对象为准
    get().then(value => {
        console.log('then1,从服务端接收到的数据是:', value);
        console.log('then1还需要继续请求服务端!');
        return get();
    }).then(value => {
        console.log('then2,从服务端接收到的数据是:', value);
        console.log('then2还需要继续请求服务端!');
        return get();
    }).then(value => {
        console.log('then3,从服务端接收到的数据是:', value);
        console.log('then3还需要继续请求服务端!');
        return get();
    }).then(value => {
        console.log('then4,从服务端接收到的数据是:', value);
        console.log('then4还需要继续请求服务端!');
        return get();
    }).then(value => {
        console.log('then5,从服务端接收到的数据是:', value);
    })
}

使用async await的方式一定程度上使异步编程串行化,也可解决回调地狱那种问题:

// 异步转同步的另一种方式:可通过async await的方式,此为es2018中新增的特性
function asyncDemo() {
    function get() {
        return new Promise(resolve => {
            setTimeout(() => {
                let res = Math.round(Math.random() * 10);
                console.log('1s后从服务端响应的数据:', res);
                resolve(res);
            }, 1000);
        })
    }
    (async () => {
        let res = undefined;
        res = await get();
        console.log(`当前时间${Date.now()},从服务端获取的数据是:${res}`);
        res = await get();
        console.log(`当前时间${Date.now()},从服务端获取的数据是:${res}`);
        res = await get();
        console.log(`当前时间${Date.now()},从服务端获取的数据是:${res}`);
        res = await get();
        console.log(`当前时间${Date.now()},从服务端获取的数据是:${res}`);
        res = await get();
        console.log(`当前时间${Date.now()},从服务端获取的数据是:${res}`);
    })()
}

最后

本人javascript的水平实在不高,本文仅作为自己学习过程的笔记记录,以便后续翻看和修改,如有理解上的问题请各位看官不吝赐教!

学习过程编写的案例代码上传至github仓库:https://github.com/huanglusong/learn-javascript

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值