Promise 基础

71 阅读3分钟

1. 同步、异步、回调

同步,能直接拿到结果,并执行下一步操作的

异步,不能直接拿到结果,可以先执行其他操作

异步操作完成,拿到结果后,如何通知?

一种是主动查询,轮询

一种是被动通知,回调

回调,就是自己写好方法,等待异步任务拿到结果后,对方直接执行此方法

满足两点,一是,你自己写的方法;二是,此方法,由另一方调用

比如,AJAX中,监听readyState属性值的变化,是通过浏览器调用XMLHttpRequest对象的onreadystatechange对应的回调,来实现的。

function f(foo) {
    setTimeout(() => {
        foo(parseInt(Math.random() * 6))
    })
}
//第一种写法
function fn(x) { console.log(x) }
f(fn)
//第二种写法
f((x) => { console.log(x) })
//第三种写法
f(console.log)

上述例子,也是通过回调。不同的调用只是函数的简写

PS:注意第三种写法,当函数的参数与使用的参数完全一致时,才可以省略

let arr = ['1', '2', '3'].map(parseInt);
console.log(arr);// [1, NaN, NaN]parseInt('1',0,arr) // 1
parseInt('2',1,arr) // NaN(parseInt第二个表示几进制)
parseInt('3',2,arr) // NaN(同上)

一般会简单地认为只有item一个参数,所以parseInt(item),可以直接简写。但map本身是由三个参数的map(item,i,arr)

2. 异步与回调的关系

异步与回调只是常见的搭配使用

异步结果可以通过轮询获取,也可以通过回调获得

具体通知过程是,由于JavaScript是单线程,一般都是由浏览器提供的功能进行异步操作,在JavaScript中留下函数地址,异步任务完成时,浏览器调用该函数的地址,同时把该异步任务的结果作为参数传给回调函数,这个函数就是给浏览器使用的,所以是回调函数

同步函数也可以使用回调,arr.forEach((item)=>{console.log(item)}),就是同步回调

3. 异步任务的结果处理

对于异步任务的结果,一般会考虑成功、失败两种场景

下面是对AJAX进行简单的封装

let ajax = (method, url, options) => {
    const { success, fail } = options;
    const xml = new XMLHttpRequest();
    xml.open(method, url);
    xml.onreadystatechange = () => {
        if (xml.readyState === 4) {
            if (xml.status >= 200 && xml.status < 300) {
                success.call(null, xml.response)
            } else {
                fail.call(null, xml)
            }
        } 
    }
    xml.send()
}
ajax('GET', 'xxx', { success() { }, fail() { } })

若改成Promise的写法

let ajax = (method, url) => {
    return new Promise((resolve, reject) => {
        const xml = new XMLHttpRequest();
        xml.open(method, url);
        xml.onreadystatechange = () => {
            if (xml.readyState === 4) {
                if (xml.status >= 200 && xml.status < 300) {
                    resolve.call(null, xml.response)
                } else {
                    reject.call(null, xml)
                }
            } 
        }
        xml.send()
    })
}
​
ajax('GET', 'xxx')
    .then(() => { }, () => { })

4. Promise 简介

Promise,异步方法并不会立即返回最终的值,而是会返回一个 promise,以便在未来某个时候把值交给使用者。

  • 是一种设计模式
  • 成功和失败回调均只接受一个参数
  • 任务成功调用resolve()resolve再去调用then里的第一个成功回调函数
  • 任务失败调用reject()reject再去调用then的第二个失败回调函数

Promise的三种状态

  • pending(待定):初始状态,既没有被兑现,也没有没拒绝
  • fulfilled(已兑现):表示操作成功
  • rejected(已拒绝):表示操作失败

处于待定状态的Promise对象最终结果,要么是fulfilled,要么是rejected。当这些情况发生时,使用then方法里对应的回调函数会被调用

return new Promise((resolve,reject)=>{
    
})

5. Promise优点

  • 对于成功和失败的命名(success+fail,success+error,done+fail)和写法,定义了统一的标准
  • 避免地狱回调,增强代码的可读性
  • 便于捕获错误

6. Promise常用方法

  • Promise.all(iterable),当iterable参数对象中所有的promise对象都成功时,才会触发成功,有一个失败就立即出发失败回调
  • Promise.allSettled(iterable),当iterable参数对象中所有的promise对象都已敲定(settled),即每个promise对象的状态要么是fulfilled,要么是rejected,会返回一个promise。并带有一个对象数组,每个对象对应每个promise的结果
  • Promise.any(iterable),当iterable参数对象中其中的一个promise成功,那就返回这个成功的值
  • Promise.race(iterable),当iterable参数对象中任意一个promise是成功或者失败时,立即将其返回,并触发对应的成功或失败回调

7. Axios

Axios是一个基于 promiseHTTP 库,可以用在浏览器和node.js 中。

详细用法可见 Axios中文文档