资讯专栏INFORMATION COLUMN

浅析Promise

darkerXi / 1726人阅读

摘要:声明,只是简单地提了提的基本使用,大牛绕道先看一个例子你需要知道是个库返回一个实例你可以把理解为,它们功能相近,只不过遵循规范我是第二个我是第二个为了防止你对这个链式调用看得眼花缭乱,我把这个给简化一下成功回调失败回调成功回调失败回调,准备

声明,只是简单地提了提promise的基本使用,大牛绕道^_^
1.先看一个例子

你需要知道
1.axios是个库
2.axios()返回一个Promise实例
3.你可以把axios()理解为$.ajax(),它们功能相近,只不过axios遵循promise规范

axios({
    url: "."
}).then((resolve) => {
    console.log(resolve)
    return "我是第二个then"
}, (reject) => {
    console.log(reject)
}).then((resolve_2) => {
    console.log(resolve_2) // "我是第二个then"
}, (reject_2) => { 
    console.log(reject_2)
})

为了防止你对这个链式调用看得眼花缭乱,我把这个给简化一下

axios({
    url: "."
}).then(成功回调, 失败回调)
  .then(成功回调2, 失败回调2)

ok,准备好了吗?下面我们先来了解Promise的一些基本概念

2.Promise的基本概念 2.1Promise的作用

Promise是专门用来解决异步编程问题的,避免了层层嵌套的回调函数[Callback Hell]
下面是一个用传统方法Callback Hell来写的异步代码
可以非常明显地看出来,Callback Hell的方式让代码的可读性变得非常差

function loadImg(src, callback, fail) {
    let img = new Image()
    img.onload = function () {
        // 成功回调
        callback(img)
    }
    img.onerror = fail // 失败回调
    img.src = src
}

let src = "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png"
loadImg(src, function (img) {
    console.log(img.width)
}, function () {
    console.log("error")
})
2.2 Promise的三个状态

pending初始态,既不成功也不失败

fulfilled异步操作成功

rejected异步操作失败

Promise对象代表一个异步操作,且只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态,peding可转化为fulfilled与rejected,但fulfilled与rejected不可相互转化

那知道这三个状态又有什么用咧?
OK,我们看下面的代码

axios({
    url: "."
}).then(成功回调, 失败回调)

axios({url: "."})
异步操作成功代表了pending -> fulfilled -> then里的第一个参数【成功回调】
异步操作失败代表了pending -> rejected -> then里的第二个参数【失败回调】

3.then和catch的链式调用

因为 Promise.prototype.thenPromise.prototype.catch 方法返回promise 对象
所以它们可以被链式调用。

OK,下面让我们仔细看一下回调触发机制究竟怎样的过程

axios({
    url: "."
}).then(成功回调, 失败回调)
  .then(成功回调2, 失败回调2)


是不是看的有点晕?没关系,下面我来详细解释一下
1.异步操作成功 -> 进入第一个then的成功回调 -> 成功回调执行异步操作成功 -> 由于又返回了一个Promise实例,其状态由于异步操作成功,由pending转为了fullfiled,所以还可以再调用第二个then -> 进入第二个then的成功回调2
2.异步操作失败-> 进入第一个then的失败回调 -> 失败回调执行异步操作成功 -> 由于又返回了一个Promise实例,其状态由于异步操作成功,由pending转为了fullfiled,所以还可以再调用第二个then -> 进入第二个then的成功回调2

你的问题:
1.为什么第一个then不论调用成功回调还是失败回调,第二个then都会调用成功回调2
答:因为第二个then调用进入哪个回调函数,完全是看第一个then返回的Promise是什么状态,换言之 —— 看异步操作成功与否


举一个栗子

axios({
    url: "."
}).then((resolve) => {
    return xxx 
    // 注意xxx是个未声明的变量
    // 浏览器会报错,说明异步操作失败了
    // 所以第一个then返回的Promise的状态是 rejected
}, (reject) => {})
    .then((resolve_2) => {
    console.log(1)
}, (reject_2) => {
    // 所以第二个then只会调用它的第二个参数
    console.log(2)
})

2.你咋不提catch咧?
因为catch就是then的一个语法糖呀
catch等价于then只有第二个参数【失败回调】的形式
上面的例子用catch,可以这么写

axios({
    url: "."
}).then((fulfilled) => {
    return xxx
    // 注意xxx是个未声明的变量
    // 所以第一个then返回的Promise的状态是 rejected
}, (rejected) => {
}).catch((rejected) => {
    // 所以直接进入catch
    console.log(2)
})
4.自己写一个Promise

第一步

// 声明一个函数 让这个函数返回一个Promise实例
let setPromise = function () {
    return new Promise()
}

第二步

// new Promise()接受一个函数
// 规定这个函数必须要有两个参数【成功回调,失败回调】
let a = 0
let setPromise = function () {
    let fn = (x, y) => {
        setTimeout(() => {
            x("success") 
            // 一定要写上异步操作成功后,会调用的回调函数
        }, 2000)
    }
    return new Promise(fn)
    // 在new的过程中一定有一句fn.call(undefined, fulfilled, rejected)
}

第三步

// 写的更装逼点,顺别把x,y换个名字【其实是规定】
let setPromise = function () {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("success")
        }, 2000)
    }) // 在new的过程中一定有一句fn.call(undefined, fulfilled, rejected)
}

第四步

// 你要做什么,就用then输入到这个Promise实例里面去
let promiseInstance = setPromise()
promiseInstance.then((success) => {
    console.log(success) // "success"
}, () => { 
    console.log("失败啦")
})

总结

let setPromise = function () {
    return new Promise((resolve, reject) => {
        // 你的异步代码
        setTimeout(() => {
            resolve("success") // 给成功回调resolve传递一个参数 "success"
            console.log("测试一下") // 两秒之后被执行
        }, 2000)
    })
}
// 你要做什么,就用then输入到这个Promise实例里面去
let promiseInstance = setPromise()
promiseInstance.then((resolve) => {
    // 异步操作执行成功后执行
    console.log(resolve) // "success"
    console.log("完美运行") // "完美运行"
}, () => {
    console.log("失败啦")
})
5.最后

其实对于Promise和then有一个更具象化的理解
Promise的中文翻译是承诺,then的中文翻译是然后
所以,你可以想象你去买橘子,结果店里没有进货,店员对你Promise,只要他店里到货,then他就会通知你

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/93767.html

相关文章

  • 浅析es6-promise源码

    摘要:主要逻辑本质上还是回调函数那一套。通过的判断完成异步和同步的区分。 主要逻辑: 本质上还是回调函数那一套。通过_subscribers的判断完成异步和同步的区分。通过 resolve,reject -> publish -> invokeCallback -> resolve,reject的递归和下一条then的parent是上一条的child来完成then链的流转 同步情况...

    fox_soyoung 评论0 收藏0
  • 浅析 JS 事件循环之 Microtask 和 Macrotask

    摘要:常见应用则是为了完成一些更新应用程序状态的较小的任务,如处理的回调和的修改,以便让这些任务在浏览器重新渲染之前执行。常见应用执行顺序的实现需要至少一个和至少一个。 简介 我们在上一篇 《浅析 JS 中的EventLoop 事件循环》 中提到一个 Event Queue,其实在事件循环中 queue 一共有两种,还有一种叫 Job Queue 其中 Event Queue 在 HTML...

    sihai 评论0 收藏0
  • 浅析 Vue 2.6 中的 nextTick 方法

    摘要:核心的异步延迟函数,用于异步延迟调用函数优先使用原生原本支持更广,但在的中,触摸事件处理程序中触发会产生严重错误的,回调被推入队列但是队列可能不会如期执行。 浅析 Vue 2.6 中的 nextTick 方法。 事件循环 JS 的 事件循环 和 任务队列 其实是理解 nextTick 概念的关键。这个网上其实有很多优质的文章做了详细介绍,我就简单过过了。 以下内容适用于浏览器端 JS,...

    fobnn 评论0 收藏0
  • Vue.nextTick浅析

    摘要:浅析的特点之一就是响应式,但数据更新时,并不会立即更新。尽管已经更新,但新增的元素并不立即插入到中。实际在中,执行了,这也是自动绑定到执行上下文的原因。在内,使用数组保存回调函数,表示当前状态,使用函数来执行回调队列。 Vue.nextTick 浅析 Vue 的特点之一就是响应式,但数据更新时,DOM 并不会立即更新。当我们有一个业务场景,需要在 DOM 更新之后再执行一段代码时,可以...

    MartinDai 评论0 收藏0
  • 切图崽的自我修养-[ES6] 异步函数管理方案浅析

    摘要:前言业务开发中经常会用到异步函数,这里简单的对异步函数以及它的各种各样的解决方案做一个浅析优缺点优点能够极大的提高程序并发业务逻辑的能力缺点异步函数的书写方式和代码执行逻辑很不直观,回调函数这种方式不太符合人类的的线性思维异步函数的执行流程 前言 业务开发中经常会用到异步函数,这里简单的对异步函数以及它的各种各样的解决方案做一个浅析 优缺点: 优点: 能够极大的提高程序并发业务逻辑的能...

    KavenFan 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<