基于JavaScript基础的异步、同步操作,promise、.then()

前提提要:代码块中均为伪代码,不是正式规格代码,只是为了方便大家观看方便易解,有错误请指正

前不久在自学ajax和vue中,发现连接服务器资源的axios库的写法是:

axios({
    url: '服务器地址'
}).then(result => {
    function(){
        ......
    }
})

一时没明白这个.then()函数是啥意思,查了网上才知道是一个叫promise的对象的函数,那问题是promise对象又是啥?接着查才知道是跟异步操作有关的,那异步操作又是啥?下面就来分析

JavaScript单线程工作

    JavaScript的代码操作严格执行单线程工作,意思就是你所写的代码,JavaScript去执行的时候都是一句一句从上到下排队执行的,形象点说就是有一个项目,去做这个项目的只有一个人,他不会影分身,只会一件事一件事的按顺序办好,这样保证了事情完成的安全。你想如果多线程的话,有一份资料,a需要拿走用,b也需要拿走用,乱套了

    但是注意!这里的单线程并不是说你的所有代码都是完全按照单线程执行,只是说JavaScript是单线程的,但是浏览器不是单线程的!换句话说,当你在JavaScript代码里调用了某些API时,这些API不是单线程的,有了它们的多线程,才能实现【异步操作】

同步操作

    同步操作就是排好队,一件事办完再办第二件事,一句一句代码执行,这样固然平稳,但是太浪费时间,打比方:你是米其林餐厅大厨,今晚要做一餐顶级大餐,在做一道菜的时候需要煮熟鸡腿再焯水拿出来冷却,你要是按照【同步操作】的话就是乖乖在这等鸡腿煮熟再准备别的菜,你老板马上开了你;【异步操作】就是在煮熟鸡腿的时间还可以做别的事比如“切蒜”、“洗菜”、“切肉”......

    这里再解释一下JavaScript同步操作的基层原理:JavaScript执行时有两个区域【控制输出台】【栈区】,当代码运行时,会在栈区先生成一个“匿名调用”,你可以理解为在工作区找了个临时工用来有活就接、接了就干

接着代码从上往下走,每遇到一个函数【被调用了】,就丢到栈区给“临时工”执行,比如第一句的console.log('global begin'),此时就会丢到栈区执行,然后再【控制台】输出语句'global begin',现在这个函数执行完毕没用了,那就从栈区丢掉

然后接着到下面两个bar和foo函数的声明代码,因为只是函数的声明,并没有任何调用,那么久不会进栈,忽略不管先

然后当遇到foo()时发现又调用了,那么foo()函数进栈,然后到foo()函数体里执行下去又发现了console,log('foo task')函数调用,接着进栈,然后再【控制台】输出'foo task',console,log('foo task')函数执行结束就出栈。

然后遇到bar()函数调用,进栈;然后进入bar()函数体里执行下去又发现console.log('bar task')函数调用,进栈;然后【控制台】输出'bar task',console.log('bar task')函数执行结束就出栈,然后到bar()出栈......

最后所有代码执行完毕,栈区清空,程序结束

异步操作

    异步操作就是中间遇到等待时间较久的函数的时候就可以在另一个线程与JavaScript的单线程同时进行,并放到一个“待办事项区”,等JavaScript单线程执行的差不多了,再从“待办事项区”把待办事项一件一件放到JavaScript的单线程中完成。

底层原理就是在【同步操作】的基础上多了三个玩意:【内部API区】、【Queue消息队列区】、【Event loop事件循环】也可以理解为监听器

然后还是按照【同步操作】的过程来,只不过当遇到【回调函数】或【API】时不入栈,而是入到【API区】或者【Queue队列】,比如这里setTimeout()函数就是【API】就是,里面的time1()函数要等1800毫秒之后才执行,那就让它先到【API区】,当然顺序还是先让setTimeout()函数入【栈】,然后time1()函数入【API区】,然后setTimeout()函数出【栈】;下一个setTimeout()函数也是一样

当所有代码从下倒下读完,那么就清空栈区,此时【Event loop】就开始监听【栈】和【队列】,当【栈区】清空了,那么就从【队列】依次取出第一个“回调函数”,压入到【栈区】执行,那么这里暂时没有回调函数,就当是暂停了一下

接下来就是把【API区】的函数放入【Queue消息队列】,当发现timer2()一秒后结束,就先到队列,然后到1.8秒的timer1(),然后再从头依次往栈里压入

再栈区还是按照【同步操作】的流程来

直到队列清空,栈也清空了,搞定,这张图会更加清楚

回调函数

    可以理解为,一个函数它自己想要做什么事,它不做,它把方法详细内容交给另一个函数执行,然后它调用,最后结果归他;或者说就是把函数A当成一个参数传给函数B,在函数B里执行完成函数A的内容

比如下面这个例子,first函数设置了定时器,我本来想按照从上到下的顺序先执行first再执行second函数,但是结果却先执行了second的内容再执行first的;于是我用【回调函数】:我用second函数当作参数传给first,本来是second要干的事,结果给了first函数去干;按照刚刚的比喻解释就是:second函数要执行自己的输出“second”这件事,但是first函数太墨迹了要等半天,那就直接把自己怎么输出“second”这个方案配方交给first,让它代替自己完成,自己就撒手不管了。

//没有回调函数时
function first(){
    setTimeout(function(){
        document.write('first'+`<br>`)
    },1000)
}
function second(){
    document.write('second'+`<br>`)
}
//本来我这样把first放在前面是为了让first先执行,再执行second,结果现在因为设置了setTimeOut,限制了first在1秒之后才执行
first();
second();//先执行了second()的内容,再执行first()的内容


//改良后
function first(c){
    setTimeout(function(){
        document.write('first'+`<br>`)
        c()//改将second函数传给first函数,在first函数里调用second就可以实现先输出first再到second了
    },1000)
}
function second(){//现在我不在外面单独调用second方法了
    document.write('second'+`<br>`)
}
first(second);//只需要执行first就能连带second一起执行

或者例子2:

Promise对象

    但是有些很复杂的程序可能会用到很多回调函数,会产生“回调地狱”

那么commenJS社区规定了一个规范:Promise对象

Promise会有两个结果,要么成功、要么失败,那么不管成功还是失败,都会有对应的反应,比如我要调用Ajax去链接服务器,如果成功了那么我就调用onFulfilled回调函数,失败了就调用onRejected回调函数

const promise = new Promise(function( resolve , reject ){
    //这里兑现“承诺”

    // resolve('Oh yes!!成功了卧槽')//resolve函数代表成功,当成功时就把传入给resolve的参数输出

    reject(new Error('shit!!!失败啦!'))//reject函数代表失败,里面是传一个“错误”对象,失败时就把传给“错误对象”的参数输出
    //注意成功、失败只能输出其一
})
promise.then(
    function(sucess){
        console.log('1')
        console.log(sucess) //这里自定义参数sucess就是resolve()的参数
    }
    ,
    function(error){
        console.log('2')
        console.log(error) //这里自定义参数error就是reject()的new Error()对象的参数
    }
    //这里注意,如果只输出成功结果,那么.then()只需要一个回调函数即可
    //但是如果只输出失败结果,那么必须要有两个函数,而且会自动判断将失败参数传给第二个函数,由第二个函数输出
)

//.then()就可以理解为一个“定时器”,他就是一个大的回调函数体,里面都是各个回调函数,.then()函数里的所有函数都会在普通函数执行完,栈区空后,从队列一个一个压回栈执行
console.log('///')//这里可以证明,结果会先打印出''再接着打印.then()函数里的内容

未完待续:看下一篇《怎么用.then()?什么是Async、Await?》

  • 27
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值