每日技术:Promise和Async/Await用法

Promise

Promise是一个容器,里面保存着某个未来才会结束的时间(通常是一个异步操作的结果)

Promise对象的基本语法:

let p = new Promise((resolve, reject) => {
    // ...
    resolve('success')
})

p.then(res => {
    console.log(res); // success
})

Promise对象特点和三个状态:

  1. 对象的状态不受外界影响
  2. 一旦状态改变,就不会再变,状态会被凝固。

例如:

let p = new Promise((resolve, reject) => {
    // ...
    resolve('success')
    console.log('after resolve')
    reject('error')
})

p.then(res => {
    console.log(res); // success
})

p.catch(err => {
    console.log(err)
})

// 运行结果:after resolve -> success

resolve下面的语句其实是可以执行的,那么为什么reject的状态信息在下面没有接收到呢?这就是因为Promise对象的状态凝固了。

new出一个Promise对象时,这个对象的起始状态就是Pending状态,再根据resolve或reject返回Fulfilled状态/Rejected状态。

Promise.prototype.then 的作用是为Promise实例添加状态改变时的回调函数。可以有两个参数

  • .then(func1, func2)
  • .then(func1)
  • .then(null, func2)

Then分别接受resolve, reject的信息

let p = new Promise((resolve, reject) => {
    // ...
    let random = Math.random(); //小于1大于0
    if (random > 0.4) {
        resolve('random > 0.4');
    } else {
        reject('random <= 0.4');
    }
})

p.then(res => {
    console.log('resolve', res)
}, res => {
    console.log('reject', res)
})

Promise.resolve() 

Promise.resolve() 将现有对象转为Promise对象的快捷方式

let p1 = Promise.resolve({name: 'xixi', age: 18})

p1.then(result => {
    console.log(result)
})

如果是Promise对象,直接返回

let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('success')
    }, 500)
})

let pp = Promise.resolve(p)

pp.then(res => {
    console.log(res)
})

console.log(pp == p)

// 输出结果:true -> success

Promise.reject() 

Promise.reject() 快速地获取一个拒绝状态的Promise对象

let p = Promise.reject(123)
console.log(p)

p.then((res) => {
    console.log(res)
}).catch(res => {
    console.log('catch', res)
})

// 输出结果:Promise {<rejected> 123} -> catch 123

Promise.all()

let p1 = Promise.resolve(123);
let p2 = Promise.resolve('hello');
let p3 = Promise.resolve('success');

Promise.all([p1, p2, p3]).then(result => {
    console.log(result);
})

// 结果:[123, 'hello', 'success']

当所有的状态都是成功状态才返回数组,否则返回reject的状态。

再来一个例子,用sleep模仿浏览器的AJAX请求

function sleep(wait) {
    return new Promise((res, rej) => {
        setTimeout(() => {
            res(wait)
        }, wait)
    })
}

let p1 = sleep(500)
let p2 = sleep(500)
let p3 = sleep(1000)

Promise.all([p1, p2, p3]).then(result => {
    console.log(result)
    // ...
    // loading
})

Promise.race() 

Promise.race() 将多个Promise实例,包装成一个新的Promise实例。哪个对象返回的快就返回哪个对象。race最终只有一个值。

Async-Await

简介

异步编程的最高境界,就是根本不用关心它异步。

async函数就是隧道尽头的亮光,很多人认为它是异步操作的终极解决方案。

async-await与promise的关系

不存在谁替代谁的,因为async-await是寄生于Promise,Generator的语法糖

规则:

  1. async表示这是一个async函数,await只能用在这个函数里面
  2. await表示在这里等待promise返回结果后再继续执行。
  3. await后面跟着的应该是一个promise对象

应用

Promise虽然一方面解决了callback回调地狱,但是相对的把回调“纵向发展”了,形成了一个回调链。

举例:

function sleep(wait) {
    return new Promise((res, rej) => {
        setTimeout(() => {
            res(wait)
        }, wait)
    })
}

sleep(100).then(result => {
    return sleep(result + 100)
}).then(result02 => {
    return sleep(result02 + 100)
}).then(result03 => {
    console.log(result03)
})

// 结果:300

后面的结果都是依赖前面的结果,改写async/await写法如下:

async function demo() {
    let result01 = await sleep(100)
    let result02 = await sleep(result01 + 100)
    let result03 = await sleep(result02 + 100)

    return result03
}

demo().then(result => {
    console.log(result)
})

// 结果:300

错误处理

既然.then()不用写了,那么catch()也不用写了,可以直接用标准的try catch语法捕捉错误

如果是reject状态,可以用try-catch捕捉

let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('error')
    }, 1000)
})

async function demo(params) {
    try {
        let result = await p
    } catch(e) {
        console.log(e)
    }
}

demo()

注意你的并行执行和循环

await in for循环

await的执行上下文必须是async函数

如果在forEach或者map的循环里使用await,这时候上下文就变成了array,而不是async function 就会报错。

以上笔记摘自:https://www.jianshu.com/p/fe0159f8beb4

原文地址:https://www.cnblogs.com/cathy1024/p/11227659.html