内容字号:默认大号超大号

段落设置:段首缩进取消段首缩进

字体设置:切换到微软雅黑切换到宋体

Promise的误区

2018-08-04 18:18 出处:清屏网 人气: 评论(0

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。

错误的脑内模型

事实上,虽然知道 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( ... )
复制代码
分享给小伙伴们:
本文标签: Promise

相关文章

发表评论愿您的每句评论,都能给大家的生活添色彩,带来共鸣,带来思索,带来快乐。

CopyRight © 2015-2016 QingPingShan.com , All Rights Reserved.

清屏网 版权所有 豫ICP备15026204号