Promise 的误区

Essentially, a promise is a returned object to which you attach callbacks, instead of passing callbacks into a function.

一直在用Promise,但一直感觉自己没有真正彻底弄明白Promise,总差那么一点。 最后发现原因很简单,是我脑内对 Promise 建立的模型错误了。于是写一篇短文。

误区

const a = new Promise(resolve => {
    const random = Math.random() > 0.5 ? 1:0
    setTimeout(() => resolve(random), 1000)
})
复制代码

这是一个一秒后会返回0或者1的promise。在浏览器的 console 里试验:

> a
< Promise {<resolved>: 1} 
> a
< Promise {<resolved>: 1} 
> a
< Promise {<resolved>: 1} 
> a
< Promise {<resolved>: 1} 
复制代码

直到地老天荒,返回的永远是1。(当然小伙伴们试验的话,也有50%可能会出现永远是0的情况,总之resolved的值不会变,谢谢回复指正)

错误的脑内模型

事实上,虽然知道 promise 是一个对象,但脑内并没有接受

> typeof a
< "object"
复制代码

在我脑内的模型,promise 是一个"函数",先定义它,然后再调用它来真正使用

const b = 定义promise
b.then( 使用promise )
复制代码

但一个Promise在定义的时候就执行了! 以第一例的promise来说,在定义了a之后

// 一秒以内
a = { status: "pending", value: undefined }
// 一秒之后
a = { status: "resolved", value: 1 }
// 这里用了简化的模型来说明,事实上并不能使用 a.status 或者 a.value 来取值
复制代码

所以虽然在定义时并不知道最后的value会是1还是0,然而一旦定义了value就已经确定下来了,不会再变化了。

为啥会有错误的脑内模型?

因为正常的使用场景,我们使用的并不是 Promise,而是return Promise的函数!

fetch(url).then( ... ) // fetch 是一个返回promise的函数
readFile(url).then( ... ) //readFile 也是一个返回promise的函数
复制代码

因为Promise在定义时就会执行,所以正常的使用方式确实是在使用时现场定义!于是就会使用函数来包裹。再以第一例来说,要让promise返回值在0和1之间随机变化,只要用函数就行了:

const createRandom = () => {
    const random = Math.random() > 0.5 ? 1:0
    return new Promise(resolve => setTimeout(resolve, 1000, random))  
    // 今天刚发现setTimeout可以接受第三个参数,简化写法
}

// 执行
createRandom().then(r => console.log(r))  // 0
createRandom().then(r => console.log(r))  // 1
createRandom().then(r => console.log(r))  // 0
createRandom().then(r => console.log(r))  // 0
createRandom().then(r => console.log(r))  // 1
复制代码

容易糊涂的地方

还有一个在学习时感觉糊涂的地方 就是各种名称,比如 resolve,reject,pending, fullfilled, respond, error 啥的,其实把定义和使用分开,一切还比较清晰

// 定义
const some = () => new Promise((resolve, reject) => {
    ... 异步操作
    ... resolve(返回值)
    ... reject("reject的原因")
})
// 使用
some.then( 
    response => { 
        // ... 处理成功返回的 response,也就是定义时 resolve 的值
    }, 
    error => {
        // ... 处理 error, 也就是定义时 reject 的值
    }
)
复制代码

常用的方法

写mock的时候一定会写一个 delay 函数

const delay = ms => new Promise(r => setTimeout(r, ms))

delay(1000).then( ... )
复制代码

Promise.resolve / Promise.reject

写mock时使用

const success = Promise.resolve(1) // 返回1的promise
const fail = Promise.reject("connection error") // rejected promise
复制代码

注意可以将一个promise 作为参数传入 Promise.resolve(), 其结果会返回promise的执行结果,也就是说在不确定一个 value 是否是 promise 时,可以安全使用

Promise.resolve(value).then( ... )
复制代码

Promise.all / Promise.race

当你希望在多个fetch request全完成时执行操作,Promise 提供了方法

Promise.all([fetch1, fetch2, fetch3]).then( ... ) 
复制代码

有少数情况需要返回一组请求里第一个返回的(不论成功失败),可以使用

Promise.race([fetch1, fetch2, fetch3]).then( ... ) 
复制代码

Promise.prototype.finally

Promise的状态:
期初是pending,异步完成后的状态有个方便的总称叫settledsettled有两种情况,成功的状态叫resolved(以前也称fullfilled),失败的叫rejected

如果不论成功还是失败都想执行一段代码(也就是在settled状态就执行),可以使用.finally

somePromise.then( ... ).catch( ... ).finally( ... )
复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值