4-Promise与async函数

Promise

介绍

  • Promise 是ES6对异步编程一种解决方案。Promise就是一个对象容器,将异步操作(同步也可以但是没有必要这么做)保存在容器内部,当异步操作执行时就可以Promise获取当前异步操作的消息。这种模式会比传统回调更强大与合理。
  • Promise 异步操作有三种状态:pending(进行中)fulfilled(已成功)rejected(已失败)。除了异步操作的结果,任何其他操作都无法改变这个状态。
  • Promise 对象只有:从 pending 变为 fulfilled 和从 pending 变为 rejected 的状态改变。只要处于 fulfilled 和 rejected ,状态就不会再变了即 resolved(已定型)。

基本用法

概念: Promise就是一个构造函数用来生成Promise实例对象
语法: Promise构造函数在生成实例对象时接收一个函数作为参数,该函数接收两个参数(由js引擎所提供)

  • 参数一 resolve 是一个函数它的作用是将Promise 的状态由 pending变为fulfilled (resolve),是一个异步操作执行成功时需要调用的方法
  • 参数二 reject 是一个函数它的作用是将Promise 的状态由 pending变为reject,是一个异步操作执行失败时需要调用的方法

以上两个参数都可以将自身接收的参数传递出去

let p = new Promise(function (resolve, reject) {
            let num = Math.random()

            if (num > 0.5) {
                resolve(num) // 成功调用resolve方法,将num传递出去
            } else {
                reject('失败了!') // 失败调用reject方法,将'失败了!'传递出去
            }
        })

prototype.then

概念:Promise实例对象生成完毕后可以使用分别指定resolve状态和reject状态的回调函数
语法: then 方法接收两个函数作为参数

  • 参数一 Promise 执行成功时的回调函数,接收resolve传递的参数
  • 参数二 Promise 执行失败时的回调 接收reject传递的参数

两个函数只会有一个被调用。

let p = new Promise(function (resolve, reject) {
            let num = Math.random()

            if (num > 0.5) {
                resolve(num) // 成功调用resolve方法
            } else {
                reject('失败了!') // 调用reject方法
            }
        })
       
p.then(
    res => console.log('成功!' + res), // resolve 的回调函数
    err => console.error(err) // reject的回调函数
)

prototype.catch

概念:Promise实例对象生成完毕后,当状态 从 pending转换为rejected状态时,then方法第二个参数的别名。reject抛出的异常会被catch所捕获
语法

p.then(
    res => console.log('成功!' + res), // resolve 的回调函数
    err => console.error(err) // reject的回调函数
)
// 就可以改写为
p.then(res => console.log('成功!' + res) // resolve 的回调函数
    .catch(err => console.error(err)) // reject的回调函数

prototype.finally

概念:在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数。一般做一些异步请求的清理工作。
语法

p.finally(() => console.log('异步操作执行完毕,无论成功失败') )

p.then(function(json) { })
  .catch(function(error) { })
  .finally(function() { });

all

概念:该方法接收一个数组包含多个promise对象并返回一个新的promise对象。
注意:当多个promise都成功完成时,all的状态也是成功。新的promise对象就会调用其resolve方法,根据数组中promise的顺序将对应的resolve返回值存入新promise的resolve数组中;如果有一个Promise失败 all的状态也是失败,失败的原因是第一个失败 promise 的结果。
语法

function fakeAjax(timeout, name , isSuccess = true) {
            return new Promise((resolve, reject) => {

                setTimeout(() => {
                    if(isSuccess) {
                        resolve(name+'-data')
                    }else {
                        reject(name)
                    }
                }, timeout)

            })
}
let p1 = fakeAjax(2500, 'p1')
let p2 = fakeAjax(1500, 'p2')
let p3 = fakeAjax(800, 'p3')

// 所有Promise都成功才会进入then,
// then的成功回调函数中的参数是一个数组,包含all方法接收多个Promise对象数组成功返回值
Promise.all([p1, p2, p3]) 
    .then(res => console.log(res)) // ['p1-data','p2-data','p3-data']
    .catch(err => console.error(err) ) 

            
let p1 = fakeAjax(2500, 'p1')
let p2 = fakeAjax(1500, 'p2', false)
let p3 = fakeAjax(800, 'p3', false)
// 只要有任何一个Promise失败all就会进入catch
// catch 回调函数接收的参数是第一个失败Promise的返回值
Promise.all([p1, p2, p3])
            .then(res => console.log(res)) 
            .catch(err => console.error(err))  //  'p3'               

any

概念:该方法接收多个 promise对象并返回一个 promise对象。多个 promise 只要有一个成功执行就会被调用promise对象方法
注意:如果有一个Promise成功 any就会返回成功,返回的值是第一个成功 promise resolve值。
语法

function fakeAjax(timeout, name, isSuccess = true) {
            return new Promise((resolve, reject) => {

                setTimeout(() => {
                    console.log(name + '执行完毕')
                    if (isSuccess) {
                        resolve(name)
                    } else {
                        reject(name)
                    }
                }, timeout)

            })
}

let p1 = fakeAjax(2500, 'p1')

let p2 = fakeAjax(1500, 'p2')

let p3 = fakeAjax(800, 'p3')

Promise.any([p1, p2, p3])
    .then(res => console.log(res)) // 'p3'
    .catch(err => console.error(err)) 

注意:any方法还处于试验阶段,尚未被所有浏览器支持

race

概念:该方法接收多个 promise对象并返回一个 promise对象。 只要有一个完成(无论成功失败) 。返回promise对象就会调用完成Promise状态
语法

let p1 = fakeAjax(2500, 'p1')

let p2 = fakeAjax(1500, 'p2')

let p3 = fakeAjax(800, 'p3', false)

Promise.race([p1, p2, p3])
    .then(res => console.log(res)) 
    .catch(err => console.error(err)) // 'p3'
    
let p1 = fakeAjax(2500, 'p1')

let p2 = fakeAjax(500, 'p2')

let p3 = fakeAjax(800, 'p3')

Promise.race([p1, p2, p3])
    .then(res => console.log(res))  // 'p2' 
    .catch(err => console.error(err))   

allSettled

概念:该方法接收多个 promise对象并返回一个 promise对象。必须所有的Promise都完成(无论成功/失败)该方法才会resolve一个数组,数组中包含接收所有Promise完成信息(status:成功 fulfilled、失败 rejected,value: 成功返回值,reason:失败原因 )
语法

let p1 = fakeAjax(2500, 'p1', false)

let p2 = fakeAjax(1500, 'p2')

let p3 = fakeAjax(800, 'p3', false)

let p4 = fakeAjax(300, 'p4')

Promise.allSettled([p1, p2, p3, p4])
            .then(res => console.log(res)) 
/* 
res 的值为 
[
    {status: "rejected", reason: "p1"},
    {status: "fulfilled", value: "p2"},
    {status: "rejected", reason: "p3"},
    {status: "fulfilled", value: "p4"},
]
*/

resolve

概念:该方法直接创建一个成功Promise

注意

  1. 该方法可以接受一个普通数据类型,或者是一个 thenabel (拥有then方法的对象)
  2. 如果传入的是 thenabel对象 该对象的then属性会修改(类似于替换效果)掉当前promis的then方法

不要在thenable上调用自身Promise.resolve 会造成无限递归
语法

// resolve普通数据
Promise.resolve(10086).then(res => console.log(res)) // 10086

// resolve promise对象 (promise对象拥有then属性所以属于thenable)
let demo = Promise.resolve(333)
        
let p = Promise.resolve(demo) 

p.then(demo => console.log(demo)) // 333
// 等价于上面的代码 Promise.resolve(333).then 替换 p.then       
// Promise.resolve(333).then(data => console.log(data)) 

// resolve 自己指定的thenable对象  
let thenabel = {
  then: function (func) {
    console.log(1231231321321)
    func('看得懂吗?')
  }
}

let p = Promise.resolve(thenabel)
p.then(data => { console.log(data) })

// resolver 配合thenabel可以抛出异常
let thenabel = {
  then: function () {
    console.log('抛出异常')
    throw new Error('异常')
  }
}

let p = Promise.resolve(thenabel)

// p.then().catch(err => console.log(err))

p.then(function() {//该方法不执行}, err => console.error(err)) // 参数二执行等价于上面的写法

reject

概念:该方法直接创建一个失败Promise
语法

Promise.reject(new Error('失败')).catch(error => console.log(error)) // "失败"

Async函数

概念: async 是 ES7 才有的与异步操作有关的关键字,他会将异步操作用同步代码的形式表现出来
语法:是一个使用async关键声明的函数。在函数内部配合await关键字将异步回调的代码改写成同步代码的格式

function demo () {
     new Promise(function (resolve, reject) {
            let num = Math.random()

            if (num > 0.5) {
                resolve(num) // 成功调用resolve方法
            } else {
                reject('失败了!') // 调用reject方法
            }
        })
        .then(res => console.log('成功!' + res))
        .catch(err => console.error(err) )
}
  
 // 下面的代码等价于上面的代码       
 async function asyncDemo() {
    try {
        let res = await new Promise(function (resolve, reject) {
        let num = Math.random()
        if (num > 0.5) {
                resolve(num) // 成功调用resolve方法
            } else {
                reject('失败了!') // 调用reject方法
            }
        })
        console.log(res, 'async')
       }
    catch (err) {
        console.log('Error:'+ err)
   }
}

asyncDemo()

注意

  1. async 函数的返回值,不是普通对象的返回值,而是Promise对象
async function test() {
            return 'hello world'
}

 // test() 等价于 new Promise((resolve) =>  resolve('hello world'))
console.log(test()) // Promise {<resolved>: "hello world"}
test().then(r => console.log(r)) //  'hello world'   

案例 axios的使用(Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中)

「拓展」 generator

介绍: generator函数是ES6提供的一种生成器对象,语法上可以将它理解成,封装了多个内部状态的一个可迭代状态机。

语法: generator 是一个普通函数,调用与普通函数相同但是有几个不同特征:

  1. function关键字与函数名之间有个星号(新版本必须包含星号)
  2. 函数体内部使用yield表达式定义迭代状态
function* helloGenerator() {
  console.log(0)  
  yield 'start';
  console.log(1)
  yield 'loading'
  console.log(2)
  return 'end';
}
  1. 函数调用时并不会执行,而是返回了一个遍历对象(指向内部状态的指针对象)
  2. 必须调用对象自身的next方法,使指针指向下一个yield声明的状态值。函数内部的代码就从当前位置向下执行到下一个yield/return的位置,并把下一个yield/return指定的值返回出去
console.log(a)
// 执行函数第一行代码到第一个yield代码   
console.log(a.next())  // 0 {value: 'start', done: false}
// 执行函数第一个yield代码到第二个yield之间的代码
console.log(a.next())  // 1 {value: "loading", done: false}
// 执行函数第二个yield代码到return之间的代码
console.log(a.next())  // 2 {value: "end", done: true}

注意:

  1. yield不是必要的,若函数Generato没有yield调用next方法时就会,函数就会一直执行到结束
  2. yield 是惰性求值的,只会在next方法指定到该yield时才会计算自己的状态值
  3. Generator函数中若没有return,函数执行到最后会返回一个value为undefined的对象

方法

  • prototype.next() 返回一个由 yield表达式生成的值。该方法可以接受一个参数作为向生成器传递的值,即当前yield的返回值
function* gen() {
  while (true) {
    let value = yield null;
    console.log(value);
  }
}

let g = gen();
g.next(1);
// "{ value: null, done: false }"
g.next(2);
// 2
// "{ value: null, done: false }"
  • prototype.return() 返回给定的值并结束生成器。该方法也可以接受一个参数效果与next相同
function* gen() {
  yield 1;
  yield 2;
  yield 3;
}

let g = gen();

g.next();        // { value: 1, done: false }
g.return("foo"); // { value: "foo", done: true }
g.next();        // { value: undefined, done: true }
  • prototype.throw() 向生成器抛出一个错误。使用 Error 的实例对调试非常有帮助.
function* gen() {
  while(true) {
    try {
       yield 42;
    } catch(e) {
      console.log("Error caught!");
    }
  }
}

let g = gen();
g.next(); // { value: 42, done: false }
g.throw(new Error("Something went wrong")); // "Error caught!"

「拓展」 fetch

介绍:Fetch API 提供了一个 JavaScript 接口,用于访问和操纵 HTTP 技术的一些具体部分,例如请求和响应。它还提供了一个全局 fetch() 方法,该方法提供了一种简单,合理的方式来跨网络异步获取资源。
这种功能以前是使用 XMLHttpRequest 实现的。Fetch 提供了一个更理想的替代方案,可以很容易地被其他技术使用,例如 Service Workers。

注意,fetch 规范与 jQuery.ajax() 主要有三种方式的不同:

  1. 当接收到一个代表错误的 HTTP 状态码时,从 fetch() 返回的 Promise 不会被标记为 reject, 即使响应的 HTTP 状态码是 404 或 500。相反,它会将 Promise 状态标记为 resolve (但是会将 resolve 的返回值的 ok 属性设置为 false ),仅当网络故障时或请求被阻止时,才会标记为 reject。
  2. fetch() 可以接受跨域 cookies;你也可以使用 fetch() 建立起跨域会话。
  3. fetch 不会发送 cookies。除非你使用了credentials 的初始化选项。

一个基本的 fetch 请求设置起来很简单。看看下面的代码:

   fetch('http://example.com/movies.json')
     .then(function(response) {
       return response.json();
     })
     .then(function(myJson) {
       console.log(myJson);
     });

这里我们通过网络获取一个 JSON 文件并将其打印到控制台。最简单的用法是只提供一个参数用来指明想 fetch() 到的资源路径,然后返回一个包含响应结果的promise(一个 Response 对象)。

当然它只是一个 HTTP 响应,而不是真的JSON。为了获取JSON的内容,我们需要使用 json() 方法。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值