前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >33·灵魂前端工程师养成-[前后分离]异步与promise

33·灵魂前端工程师养成-[前后分离]异步与promise

作者头像
DriverZeng
发布2022-10-31 18:10:04
8860
发布2022-10-31 18:10:04
举报

-曾老湿, 江湖人称曾老大。


-多年互联网运维工作经验,曾负责过大规模集群架构自动化运维管理工作。 -擅长Web集群架构与自动化运维,曾负责国内某大型金融公司运维工作。 -devops项目经理兼DBA。 -开发过一套自动化运维平台(功能如下): 1)整合了各个公有云API,自主创建云主机。 2)ELK自动化收集日志功能。 3)Saltstack自动化运维统一配置管理工具。 4)Git、Jenkins自动化代码上线及自动化测试平台。 5)堡垒机,连接Linux、Windows平台及日志审计。 6)SQL执行及审批流程。 7)慢查询日志分析web界面。


JS异步编程模型


什么是异步?什么是同步?

网上的解释经常混淆异步与回调。

代码语言:javascript
复制
## 如果能直接拿到结果,那就是同步
# 例如:
# 1.在医院挂号,你拿到号才会离开
# 2.QQ的在线发送文件,对方发送完,你接收完文件才能关闭QQ


## 如果不能直接拿到结果,那就是异步
# 例如:
# 1.你在餐厅门口等位,叫号,你拿到号可以去逛街
# 那么什么时候才能去吃饭呢?
# 你可以每隔几分钟回去问一次,还剩几个。(轮询)
# 你也可以扫码用微信接收通知。(回调)
# 2.QQ的离线发送文件。

以上是生活中的例子,那么我们接下来以代码为例子。

代码语言:javascript
复制
## 以AJAX为例
# request.send()之后,并不能直接得到respone
# 不信,可以console.log(request.respone)试试
# 必须等到readyState变为4后,浏览器回头调用request.onreadystatechange函数
# 我们才能得到request.response
# 这跟餐厅给你发微信提醒的过程类似


## 回调callback
# 你写给自己用的函数,不是回调
# 你写给别人用的函数,就是回调
# request.onreadystatechange就是我写给浏览器调用的
# 意思就是,你(浏览器)回头调用一下这个函数。
# 在中文中「回头」也有「将来」的意思,如:「我回头请你吃饭」

异步和回调的关系

代码语言:javascript
复制
## 关联
# 异步任务需要在得到结果时通知JS来拿结果
# 怎么通知呢?
# 可以让JS写留一个函数地址(电话号码)给浏览器
# 异步任务完成时,浏览器调用该含税地址即可(拨打电话)
# 同时把 结果作为参数传给该函数(电话说,可以来吃饭了)
# 这个函数是我写给浏览器调用的,所以是回调函数

## 区别
# 异步任务需要用到回调函数来通知结果。
# 但回调函数不一定只用在异步任务里
# 回调可以用到同步任务里
# array.forEach(n=>console.log(n))就是同步回调

如何判断一个函数时异步还是同步

如果一个函数的返回值处于下面几种情况,就是异步。

1.setTimeout 2.AJAX(即XMLHTTPRequest) 3.AddEventListener

求都嘛得~ 我听说AJAX可以设置为同步的。

傻X前端才会把AJAX设置为同步,这样做会使请求期间页面卡住。

我们试一下把之前代码改成同步,整个页面都会卡主。

代码语言:javascript
复制
getJSON.onclick = () =>{
    const request = new XMLHttpRequest()
    request.open('GET','/zls.json',false)
    request.onreadystatechange = () =>{
        if(request.readyState === 4 ){
            if(request.status >= 200 && request.status < 300){
                console.log(request.response)
                const object = JSON.parse(request.response)
                myName.textContent = object.name
            }
        }
    }
    request.send()
}

我点了两个请求,先请求json再请求xml,会发现,必须等到json请求返回之后,才会发起对xml的请求。

我们改回异步试试。

代码语言:javascript
复制
getJSON.onclick = () =>{
    const request = new XMLHttpRequest()
    request.open('GET','/zls.json')
    request.onreadystatechange = () =>{
        if(request.readyState === 4 ){
            if(request.status >= 200 && request.status < 300){
                console.log(request.response)
                const object = JSON.parse(request.response)
                myName.textContent = object.name
            }
        }
    }
    request.send()
}

两个请求可以同时触发,异步返回结果。


如果异步任务有两个结果怎么办?

当我们的异步结果有两个,一个是成功,一个是失败,我们该怎么做?

方法一:回调接受两个参数

代码语言:javascript
复制
fs.readFile('./1.txt',(error,data)=>{
    if(error){console.log('失败');return}
    console.log(data.toString())//成功
})

方法二:搞两个回调呗

代码语言:javascript
复制
ajax('GET','/1.json',data()=>{},error()=>{})
//前面函数是成功回调,后面函数是失败回调
ajax('GET','/1.json',{
    success:()=>{},fail:()=>{}
})
//接受一个对象,对象有两个key,表示成功和失败

但是...特么的,只要有但是,那么但是之前的都是废话,上面两种方法都不行。

不管是方法一,还是方法二,都有问题。

1.不规范,名称五花八门,因为是约定,有人用success + error ,有人用success + fail,有人用done + fail

2.容易出现回调地狱,代码变得看不懂

3.很难进行错误处理

回调地狱举例:

代码语言:javascript
复制
getUser(user=>{
    getGroups(user,(group)=>{
        groups.forEach((g)=>{
            g.filter(x => x.ownerId === user.id).forEach(x => console.log(x))
        })
    })
})

这还只是4层回调,你能想象20层回调么?

网上吐槽回调地狱的图片【HaDoGen】

如何解决上述的三个问题呢?

1.规范回调的名字或顺序 2.拒绝回调地狱,让代码可读性更强 3.很方便的捕获错误


前端程序猿开始翻书了

  • 1976年,Daniel P.Friedman 和 David Wise。
  • 俩人提出了Promise思想。
  • 后人基于此发明了Future、Delay、Deferred等。
  • 前端结合Promise和JS,制定了Promise/A+规范。
  • 该规范详细描述了Promise的原理和使用方法。

AJAX封装

代码语言:javascript
复制
ajax = (method,url,options)=>{
    const {success,fail} = options //析构赋值
    const request = new XMLHttpRequest()
    request.open(method,url)
    request.onreadystatechange = () =>{
        if(request.readyState === 4){
            //成功就调用 success,失败就用 fail
            if(request.status < 400){
                success.call(null,request.respone)
            }else if(request.status >= 400){
                fail.call(null,request,request.status)
            }
        }
    }
    request.send()
}

// 调用封装函数
ajax('get','/xxx',{
    success(response){},fail:(request,status)=>{}
})

//左边是function缩写,右边是箭头函数,记下来,别再问我

Promise写法

Promise说,上面这个代码太傻了,我们使用Promise写法吧。因为之前我们说的那三个原因,不规范、回调地狱、很难错误处理。

代码语言:javascript
复制
// 先改一下调用姿势
ajax('get','/xxx',{
    success(respone){},fail:(request,status)=>{}
})

// 上面代码,用到了两个回调,还是用了 success 和 fail

// 改成Promise写法
ajax('get','/xxx').then((respone)=>{},(request)=>{})

// 虽然也是回调
// 但是不用记success和fail了
// then的第一个参数就是success
// then的第二个参数就是fail

// 请问ajax()返回了个啥?
// 返回了一个含有.then()方法的对象呗
// 那么再请问,如何得到这和个含有.then()的对象呢?
// 那就要改造ajax的源码了,如下:

ajax = (method,url,options)=>{
    return new Promise((resolve,reject)=>{
        const {suuccess,fail} = options
        const request = new XMLHttpRequest()
        request.open(method,url)
        request.onreadystatechange = () =>{
            if(request.readyState === 4){
                if(request.status < 400){
                    resolve.call(null,request.respone)
                }else if(request.status >= 400){
                    reject.call(null,request)
                }
            }
        }
        request.send()
    })
}

背下来下面五个单词即可,等你用熟了,自然就掌握了Promise。

代码语言:javascript
复制
return new Promise((resolve,reject)=>{}

小结:

第一步: return new Promise((resolve,reject)=>{...}) 任务成功则调用resolve(result) 任务失败则调用reject(error)

第二步: 使用.then(success,fail)传入成功和失败函数

点到为止: Promise先介绍到这里,高级用法,我们后面再说,先把五个单词背会


封装AJAX的缺点

1.post无法上传数据 request.send(这里可以上传数据)

2.不能设置请求头 request.setRequestHeader(key,value)

怎么解决呢? 花时间把ajax写到完美(有时间可以做) 使用JQuery.ajax(这个可以) 使用axios(这个库比JQuery逼格高)


JQuery.ajax

已经非常完美,进入JQuery文档,搜索ajax找到jQuery.ajax,看看参数说明,然后直接看代码示例,看看jQuery的封装,就知道自己的封装有多么的辣鸡了。

封装的优点: 支持更多形式的参数 支持Promise 支持的功能超多

我们需要掌握jQuery.ajax嘛? 不用,现在的专业前端都在用axios 写篇博客,罗列一下功能,就可以忘掉jQuery了。

axios

jQuery.ajax我们可以忘了,目前,最新的AJAX库,axios划重点,显然它抄袭了jQuery的封装思路。如果有人问我你记得axios的API吗?对不起,不记得,但是我写了博客...

代码示例:

代码语言:javascript
复制
axios.get('/5.json')
    .then(respone =>
        console.log(response)
    )

axios高级用法

JSON自动处理 axios如果发现响应的Content-Type是json,就会自动 调用JSON.parse,所以说,正确设置Content-Type是好习惯。

请求拦截器 你可以 在所有请求里加东西,比如加查询参数

响应拦截器 你可以在所有响应里加东西,甚至改内容

可以生成不同实例 不同的实例可以设置不同的配置,用于复杂场景。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-05-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • JS异步编程模型
  • AJAX封装
  • Promise写法
  • axios
相关产品与服务
堡垒机
腾讯云堡垒机(Bastion Host,BH)可为您的 IT 资产提供代理访问以及智能操作审计服务,为客户构建一套完善的事前预防、事中监控、事后审计安全管理体系,助力企业顺利通过等保测评。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档