es6异步解决方案,解决异步编程的方法

时间: 2019-12-10阅读: 69标签: 异步promise是什么?

简单介绍下这几个的关系
为方便起见 用以下代码为例简单介绍下这几个东西的关系,

本文你将看到:

Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。简单来说,promise的作用就是将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。

async function buildData(name) {
      try {
        let response1 = await axios.get('/api/user?name=' + name);
        let userInfo = response1.data;

        let response2 = await axios.get('/api/topics?user_id' + userInfo._id);
        let posts = response2.data;
        // i got it.
      } catch(err) {
        console.log(err);
      }  
    }

    buildData('xiaoming');

promise介绍以及用法
promise常用api
demo使用Promise实现一个简单axios
async方法

promise的特点

async

在函数声明前使用async关键词修饰 说明函数中有异步操作

1.promise基本用法

Promise 是异步编程的一种解决方案。
从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。
我们先通过一个例子来谈谈promise。

function dome(t) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, t, 'resolve');
  });
}
dome(1000).then((value) => {
  console.log(value);
})

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。
resolve函数:将Promise对象的状态从“未完成”变为“成功”并将异步操作的结果,作为参数传递出去
reject函数:将Promise对象的状态从“未完成”变为“失败”,将异步操作报出的错误,作为参数传递出去。
下面我们为你说说,到底发生了什么:
当demo执行时,新建了一个promise实例,并且在t毫秒以后,执行resolve函数。即表示成功的函数。
then可以接受两个回调函数作为参数。第一个代表成功时调用,第二个代表失败时调用。
因为我们触发了resolve,并且返回‘resolve’,所以,出发了then第一个回调函数会打印value会打印出 resolve。
如果,promise实例即没有执行resolve也没有执行reject,则这两个回调函数都不会调用,例如

function dome(t) {
  return new Promise((resolve, reject) => {});
}
dome(1000).then((value) => {
   console.log(1);
},(value) => {
   console.log(2)
})

运行结果,将什么也不打印。

图片 1

Paste_Image.png

如果调用resolve:

function dome(t) {
  return new Promise((resolve, reject) => {
     resolve('ok')
 });
}
dome(1000).then((value) => {
   console.log(value);
},(value) => {
   console.log(2)
})

结果为:

图片 2

Paste_Image.png

如果调用reject:

function dome(t) {
  return new Promise((resolve, reject) => {
     reject('err')
 });
}
dome(1000).then((value) => {
   console.log(value);
},(err) => {
   console.log(err)
})

结果:

图片 3

Paste_Image.png

那么promise的执行的先后顺序是如何呢?

let promise = new Promise((resolve, reject) => {
  console.log('p');
  resolve();
});
promise.then( () => {
   console.log('ok');
});
console.log('no');

结果:

图片 4

Paste_Image.png

① 对象的状态不受外界影响:promise异步操作有三种状态:进行中,已成功,已失败。只有异步操作才能改变这个状态。 ②一变则不变:promise状态一旦改变,就不会再发生变化,promise对象改变的两种可能,进行中—已成功,进行中—已失败。

await

等待 后面的代码执行完毕 再继续向下执行

2.then方法的链式写法

promise实例调用then方法以后,返回的是一个新的promise实例。因此可以在then方法的后面继续调用then方法。
例如:

function dome(t) {
  return new Promise((resolve, reject) => {
      setTimeout(resolve, t, t*2);
 });
}
dome(1000).then( value => {
      return dome(value)
}).then( value => {
      console.log('sec'+value)
},err => {
      console.log('err'+err)
})

即结果为

图片 5

Paste_Image.png

promise的基本用法

promise

Promise 是一个对象,从它可以获取异步操作的消息,知道异步函数是完成了还是出错了。
axios返回的结果就是一个promise

catch方法

Promise.prototype.catch方法是.then(null, rejection)的别名。

function dome(t) {
  return new Promise((resolve, reject) => {
      setTimeout(reject, t, '发生错误');
 });
}
dome(1000).catch( err=>  {
         console.log(err)
})

结果:

图片 6

Paste_Image.png

如果Promise状态已经变成Resolved,再抛出错误是无效的。
并且Promise 对象的错误会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。
例如:

dome(1000).then( value => {
      return dome(value)
}).then( value => {
      console.log('sec'+value)
}).catch( err=>{})

上面代码中,一共有三个promise对象:一个由dome产生,两个由then产生。它们之中任何一个抛出的错误,都会被最后一个catch捕获。
所以建议使用catch方法,尽量不要用then方法的第二个参数,因为catch可以捕获到前面then方法中的错误。

promise对象是一个构造函数,用来生成promise实例例子:

try catch

try catch JavaScript的异常捕获机制,凡是在try语句块中的代码出错了,都会被catch捕获。

上面的代码就是说

  1. buildData 这个函数被 async 修饰 说函数中有异步操作
  2. await 等待异步操作结果
  3. 如果有错误发生 使用try catch 捕获异常

上面说的太过简单,简要的说明下 各个东西是干啥的。这里的核心是 promise 下面会逐个介绍

all方法

Promise.all方法可以将多个 Promise 实例,包装成一个新的 Promise 实例。
在多个实例中,加入有一个实例被rejected,则新的实例就会变成rejected。
只有当所有实例状态都变成fulfilled,则新的实例状态才会变成fulfilled。
所有实例的返回值将组成一个数组,返回给新实例。
例如

function dome1() {
  return new Promise((resolve, reject) => {
      resolve('dome1')
 });
}
function dome2() {
  return new Promise((resolve, reject) => {
      resolve('dome2')
 });
}
function dome3() {
  return new Promise((resolve, reject) => {
      resolve('dome3')
 });
}
Promise.all([dome1(),dome2(),dome3()]).then((result) => {
    console.log(result)
}).catch(err => {
    console.log(err)
})

结果

图片 7

Paste_Image.png

因为每个势力都是resolve 所以返回了包含每个实例返回值组成的数组。

function dome1() {
  return new Promise((resolve, reject) => {
      resolve('dome1')
 });
}
function dome2() {
  return new Promise((resolve, reject) => {
      reject('err2')
 });
}
function dome3() {
  return new Promise((resolve, reject) => {
      resolve('dome3')
 });
}
Promise.all([dome1(),dome2(),dome3()]).then((result) => {
    console.log(result)
}).catch(err => {
    console.log(err)
})

结果:

图片 8

Paste_Image.png

第二个reject所以最终返回了 err

const promise = new Promise(function(resolve, reject) { // ... some code if (/* 异步操作成功 */){ resolve(value); } else { reject(error); }});

Promise


Promise字面上讲,是一个承诺。这个承诺有三个状态

  • pending 进行中(悬而未决)
  • fulfilled 已成功(以满足)
  • rejected 已失败(已拒绝)

从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

Promise对象有以下两个特点:

  1. 对象的状态不受外界的影响。只有异步操作的结果可以决定当前是哪种状态。
  2. 状态一旦改变 就不会再变,任何时候都可以得到这个结果。promise对象状态的改变只有两种情况,
    • pending 到 fulfilled
    • pending 到 rejected

只要这两种情况发生,状态就凝固了,不会再改变了,会一直保持这个结果,这时就定型了 resolved。
如果改变已经发生了,任何时候添加回调函数,得到的都是这个结果。

因为创建Promise对象时,回调函数中有resolve和reject两个参数,后续的resolved统一指的是fulfilled状态,不包括rejected状态

一个Promise对象一旦状态确定了,它的使命也就结束了。后面的代码都不应该再执行了,最好return resolve();
如果状态已经resolve了,再在后面抛出错误也是无效的,也不会改变状态为rejected,后面有异常也不会抛出。

race

race和all方法类似,只不过在在逻辑上只要所有子实例中有一个状态发生改变,就会立马把状态传递给新的实例。在这里就不在写例子了。大家自己研究。
reject方法与reject方法

Promise.resolve('cxh')
// 等价于
new Promise(resolve => resolve('cxh'))

如果参数是Promise实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。
如果参数是一个带有then方法的实例,Promise.resolve方法会将这个对象转为Promise对象,然后就立即执行该对象的then方法。
加入参数不是对象,则Promise.resolve方法返回一个新的Promise对象,状态为Resolved,Promise.resolve方法的参数,会同时传给回调函数。
例如

var p = Promise.resolve('cxh');
 p.then(function (s){
    console.log(s)
});

不带有任何参数则,Promise.resolve方法返回一个新的Promise对象,状态为Resolved。
Promise.reject()方法也会返回一个新的 Promise 实例,该实例的状态为rejected。

其中接受的参数是resolve和reject两个函数resolve的作用:将promise对象的状态由进行中—已完成。并将异步操作的结果作为参数传递出去rejected的作用:将promise对象的状态由进行中—已失败,并将异步失败的原因作为参数传递出去。注意:调用resolve或reject并不会终结promise的参数函数的执行例子:

Promise对象如何知道异步操作结果又如何传递


Promise对象如何知道异步操作的结果呢,那就是回调函数了,一个表示成功resolve,一个表示失败reject,

ES6 规定,Promise对象是一个构造函数,用来生成Promise实例。
下面代码创造了一个Promise实例。

var promise = new Promise(function(resolve, reject) {
    // ... some code
    console.log(我一创建就执行了)
    if (/* 异步操作成功 */){
      resolve(value);
    } else {
      reject(error);
    }
  });

Promise新建后,就会立即执行,返回一个Promise对象。
Promise构造函数需要一个函数作为参数,这个函数有两个参数,分别是resolve和reject,
它们是两个函数,由 JavaScript 引擎提供,不用自己部署

  • resolve: 把Promise状态 从 pending 变为 resolved ,在异步操作成功时调用,并将异步操作的结果,作为参数传递出去
  • reject: 把Promise状态 从 pending 变为 reject ,在异步操作失败时调用,并把错误作为参数传递出去
    此外,reject方法的作用,也等同于抛出异常。reject的参数会被catch捕获。即便没有调用reject,如果执行过程中出错了,也会被catch捕获。

所以:

  1. 异步操作成功时,把结果告诉resolve回调函数 异步操作失败 把错误告诉reject回调函数
  2. resolve 和 reject 回调函数 还有一个作用就是把 结果传递出去

done方法

因为Promise内部的错误不会冒泡到全局,我们无法捕捉到抛出的错误怎么办?
所以提出一个done方法,在回调链末端,保证任何错误都能抛出。

Promise.prototype.done = function (fulfilled, rejected) {
  this.then(fulfilled, rejected)
    .catch(function (reason) {
      setTimeout(() => { throw reason }, 0);
    });
};

上面的方法很简单,就是给Promise添加一个done方法,在done方法内部,用this指向promise添加then和catch方法。

new Promise((resolve, reject) = { resolve(1); console.log(2);}).then(r = { console.log(r);});// 2// 1

Promise对象如何使用异步函数的执行结果


通过then方法获取异步操作的结果。
Promise实例有两个方法:

  • then 指定了resolve状态和reject的回调函数
  • catch 专门用来捕获Promise对象产生的错误

then和catch方法返回的是一个新的Promise对象,因为Promise对象具有then和catch方法,所以可以一直.then和.catch下去
axios返回的也是Promise对象,这也是为什么axios可以那么链式操作了

then方法的作用就是干这个

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

then方法的参数是两个回调函数,都接受Promise对象传出的值作为参数:

  • 第一个参数是resolve状态的回调函数
  • 第二个参数是reject的回调函数, 这个参数是可选的

通常这个参数也不写,因为Promise实例还有一个方法叫catch是专门用来捕获异常的。

finally方法

finally方法用于指定不管Promise对象最后状态如何,都会执行的操作。

Promise.prototype.finally = function (callback) {
  let parmise = this.constructor;
  return this.then(
    value  => parmise.resolve(callback()).then(() => value),
    reason => parmise.resolve(callback()).then(() => { throw reason })
  );
};

上面代码调用了resolve(1)以后,后面的console(2)还是会执行,并且会首先打印出来。这是因为立即resolved的promise是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。

catch


catch 是 .then(null, rejection)的别名,用于指定发生错误时的回调函数。

一旦catch前面的任何一个Promise发生异常,都会被catch捕获,包括Promise函数创建的Promise,还有.then返回的Promise,甚至catch前面如果还有一个catch在这个catch抛出的异常也会被后一个catch捕获。

也就是说:
Promise对象的错误具有冒泡性质,会一直向后传递,直到被捕获为止,也即是说,错误总会被下一个catch语句捕获。

所以,既然这个catch这么厉害,then函数中的第二个参数常常被省略了,然后被这个catch方法替代。

所以通常这么写:
promise.then().catch()
promise.then().then().catch()
promise.then().then().catch().then().catch()

所以下面例子第二种写法好些。

// bad
promise
  .then(function(data) {
    // success
  }, function(err) {
    // error
  });

// good
promise
  .then(function(data) { //cb
    // success
  })
  .catch(function(err) {
    // error
  });

一般总是建议,Promise 对象后面要跟catch方法,这样可以处理 Promise 内部发生的错误。catch方法返回的还是一个 Promise 对象,因此后面还可以接着调用then方法和catch方法。

demo实例

下面我们用promise写一个异步获取数据方法:

  class Axios {
    constructor(){}
    post(url){
        console.log(1)
        return this.getData(url,'POST')
    }
    get(url){
        console.log(2)
        return this.getData(url,'GET')
    }
    getData(url,methods){
        var promise = new Promise(function(resolve, reject){
            var client = new XMLHttpRequest();
            client.open(methods, url);
            client.onreadystatechange = handler;
            client.responseType = "json";
            client.setRequestHeader("Accept", "application/json");
            client.send();

            function handler() {
               if (this.readyState !== 4) {
                return;
               }
               if (this.status === 200) {
                  resolve(this.response);
               } else {
                  reject(new Error(this.statusText));
                }
            };
        });
        return promise;
    }
}

var axios = new Axios;
axios.get('http://localhost:3000/getData').then((value) => {
    console.log(value);
});
axios.post('http://localhost:3000/postData').then((value) => {
    console.log(value);
});
console.log("cxh")

node.js部分,我们使用express

var express = require('express');
var router = express.Router();

router.get('/', function(req, res, next) {
  res.render('index');
});
router.get('/getData', function(req, res, next) {
  res.json({ "code": '100',"result":"get success!" });
});
router.post('/postData', function(req, res, next) {
  res.json({ "code": '100',"result":"post success!" });
});
module.exports = router;

下面是我们的运行结果:

图片 9

Paste_Image.png

then的用法

Promise 还有两个常用方法:

  • Promise.all() :将多个Promise实例,包装成一个新的Promise实例。内部所有的Promise的状态都变成fulfilled,这个Promise状态才会变成fulfilled,返回值是一个数组,但是只要有一个 rejected 这个Promise对象就会变成rejected 返回第一个被reject的实例的返回值
  • Promise.race():跟all方法一样,只是race就想是赛跑,谁先有结果,返回谁的结果。不会等到所有的Promise都执行完。

async 函数

async 函数只不过是Generator 函数的语法糖。
async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已。

  async function () {
        var res1 = await axios.get('http://localhost:3000/getData');
        var res2 = await axios.get('http://localhost:3000/getData?name='+res1');
       console.log(res1);
       console.log(res2);
};

当执行上面这段代码的时候,遇到await就会跳出,继续执行下面的代码,直到axios拿到数据,再继续向下下执行。
await命令后面是一个 Promise 对象。如果不是,会被转成一个立即resolve的 Promise 对象。
假如,我们需要请求一个api,拿到返回的数据,作为参数再去请求另一个api,拿到数据后在作为参数请求下一个,那么用then,该怎么写?依照上面的demo。

axios.get('http://localhost:3000/getData').then((value) => {
    return axios.get('http://localhost:3000/getData?name='+value.code);
}).then((res) => {
    return axios.get('http://localhost:3000/getData?name='+res.code);
}).then( (value) => {
    console.log(value)
}).catch(err => {});

node部分我们改成:

router.get('/getData', function(req, res, next) {
  var cxh = req.query.name;
  if(cxh && cxh == '100'){
        res.json({ "code": '200',"result":"get2 success!" });
  }else if(cxh && cxh == '200'){
        res.json({ "code": '300',"result":"finish!" });
  } else{
        res.json({ "code": '100',"result":"get success!" });
  }
});

运行结果

图片 10

Paste_Image.png

要用n个then方法。
如果改称async函数呢?

class Axios {
    constructor(){}
    post(url){
        console.log(1)
        return this.getData(url,'POST')
    }
    get(url){
        console.log(2)
        return this.getData(url,'GET')
    }
    getData(url,methods){
        var promise = new Promise(function(resolve, reject){
            var client = new XMLHttpRequest();
            client.open(methods, url);
            client.onreadystatechange = handler;
            client.responseType = "json";
            client.setRequestHeader("Accept", "application/json");
            client.send();

            function handler() {
               if (this.readyState !== 4) {
                return;
               }
               if (this.status === 200) {
                  resolve(this.response);
               } else {
                  reject(new Error(this.statusText));
                }
            };
        });
        return promise;
    }
}

var axios = new Axios;
async function getData(){
    let res = await axios.get('http://localhost:3000/getData');
    let val = await axios.get('http://localhost:3000/getData?name=' + res.code);
    let cxh = await axios.get('http://localhost:3000/getData?name=' + val.code);
    console.log(res)
    console.log(val)
    console.log(cxh)
} 
getData();

结果:

图片 11

Paste_Image.png

假如,上面三个await方法中有一个出现了reject,那么那么整个async函数都会中断执行。
如果代买如下:

var axios = new Axios;
async function getData(){
    let res = await axios.get('http://localhost:3000/getData');
    let val = await axios.get('http://localhost:3000/getData?name=' + res.code);
    let cxh = await axios.get('http://localhost:3000/getData?name=' + val.code);
    console.log(res)
    console.log(val)
    console.log(cxh)
    let fin =  await axios.post('http://localhost:3000/postData');
} 
getData();

假如上面三个方法中有一个出错,那么整个函数都会执行,也就是最后一个虽然和前面三个没关系,依然执行不了。那么怎么解决?

async function getData(){
    try{
        let res = await axios.get('http://localhost:3000/getData');
        let val = await axios.get('http://localhost:3000/getData?name=' + res.code);
        let cxh = await axios.get('http://localhost:3000/getData?name=' + val.code);
        console.log(res)
        console.log(val)
        console.log(cxh)
    }catch(err){

    }

    let fin =  await axios.post('http://localhost:3000/postData');
} 

这样就ok了。
2017年8月13日

promise实例生成后,用then方法分别指定resolved状态和rejucted状态的回调函数。例子:

现有对象转为Promise对象

Promise.resolve方法就起到这个作用

Promise.resolve('foo')
// 等价于
nnew Promise(function (resolve) {
    resolve('foo')
})

Promise.resolve方法的参数分成四种情况:

  • 参数是一个Promise实例 :不做任何修改、原封不动地返回这个实例。
  • 参数是一个thenable对象 :将这个对象转换为Promise对象,然后立刻执行thenable的then方法
  • 参数不是具有then方法的对象,或根本就不是对象 :反回一个新的Promise对象,状态为resolved。
  • 不带有任何参数: 直接返回一个resolved状态的Promise对象
    立即resolved的对象,是在本轮事件循环结束时,而不是在下一轮循环时间开始时
setTimeout(function () {
  console.log('three');
}, 0);

Promise.resolve().then(function () {
  console.log('two');
});

console.log('one');

上面代码中,setTimeout(fn,0),在下一轮循环事件开始执行
Promise.resolve()在本轮事件循环结束时执行
console.log('one')立刻执行,
因此上面的打印顺序是 one two three

promise.then(function(value) { // success}, function(error) { // failure});

直接返回一个状态为rejected Promise对象


Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。

  var p = Promise.reject('出错了');
    //等价于
  new Promise(function (resolve,reject) {
      reject('出错了');
  })

Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。不会像Promise.resolve那样,根据不同的情况包装Promise

then方法可以接受两个回调函数作为参数,第一个回调函数是当promise对象状态是resolve(已完成)的时候调用,第二个回调函数(可选)是当promise对象状态是reject(已失败)的时候调用。如例子:

async和await


async函数是Generator函数的语法糖,将Generator的星号换成async 将yield换成await

Generator是一个状态机,封装了多个内部状态,执行 Generator 函数会返回一个遍历器对象,返回的遍历器对象,可以使用next依次遍历 Generator 函数内部的每一个状态。Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。Generator 函数的执行必须靠执行器。

async函数比Generator函数更好用

  • 自带执行器,执行起来,跟调用普通函数一样
  • async和await 语义更清晰,async表示函数里有异步操作,await 表示紧跟在后面的表达式需要等待结果
  • await后面啥都可以跟,可以是Promise 也可以是对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)
  • async函数的 返回值是 Promise

正常情况下,await命令是个Promise对象,如果不是 会被转成一个 立即 resolved的对象
async函数完全可以看作多个异步操作,包装成的一个 Promise 对象(因为await 函数返回的是Promise对象),而await命令就是内部then命令的语法糖。

然而,然而,我们没写错误处理。

async function f() {
  return 'hello world';
}
f().then().catch()

正常情况下 async 函数中return结果会使Promise对象变为 resolved状态,返回值作为then方法回调函数的参数,而出错则会使Promise对象的变为reject状态,错误会被catch捕获。

因为 async函数 相当于对 多个Promise的封装,所以必须等到内部所有的await命令执行完,才会改变自己的状态为resolved,除非 碰到return语句或者抛出了异常。
也就是说,正常情况下 只有async函数内部的异步操作执行完,才会执行then后面的语句。

只要一个await后面的Promise变为rejected,整个async函数就会中断执行,整个async返回的Promise对象就会是rejected状态

async function f() {
  await Promise.reject('出错了');
  await Promise.resolve('hello world'); // 不会执行
}

因为第一个await后面的对象reject了,所以整个async函数就中断执行了

有时,我们希望即使前一个异步操作失败,也不要中断后面的异步操作。
这时可以将第一个await放在try...catch结构里面,这样不管这个异步操作是否成功,第二个await都会执行。

await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try...catch代码块中。

function timeout(ms) { return new Promise((resolve, reject) = { setTimeout(resolve, ms, 'done'); });}timeout(100).then((value) = { console.log(value);});// 结果是done

try catch


try catch是JavaScript的异常处理机制,把可能出错的代码放在try语句块中,如果出错了,就会被catch捕获来处理异常。如果不catch 一旦出错就会造成程序崩溃。

如果有多个await命令,可以将其都放在try catch结构中,如果执行出错,catch会去捕获异常

async function f() {
    try {
     await Promise.reject('出错了');
     console.log('上面已经出错了');
     return await Promise.resolve('hello world');
    } catch(e) {
        console.log(e);
    }
  }

  f()
  .then(v => console.log(v))

catch会去捕获try代码块中的错误,只要有一个抛出了异常,就不会继续执行,所以上面的代码不会打印上面已经出错了也不会执行return await Promise.resolve('hello world');
因为使用了trycatch 所以 async 是顺利执行完成的,其中的报错 被 try catch处理了,所以异常不会被async返回的Promise的catch捕获,因此async返回的Promise对象状态是resolved。

链式的then用法

如果异步函数没有依赖关系,最好并发执行


await 会等待后面的异步操作执行完毕,才会继续执行

let foo = await getFoo();
let bar = await getBar();

上面的代码会顺序执行,
如果需要多个await没有相互依赖,最好让他们同时触发,可以使用以下两种方式:

  • 使用Promise.all() 包装一个新的Promise对象
let [foo, bar] = await Promise.all([getFoo(), getBar()]);
  • 不等待分别执行,返回新的Promise对象
//没用await 立即执行返回 Promise对象
let fooPromise = getFoo();
let barPromise = getBar();
// 等待 Promise对象的结果 之前也说过 await就像是then的语法糖
let foo = await fooPromise;
let bar = await barPromise;

then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法例子

getJSON("/post/1.json").then(function(post) { return getJSON(post.commentURL);}).then(function funcA(comments) { console.log("resolved: ", comments);}, function funcB(err){ console.log("rejected: ", err);});

上面代码中,第一个then方法指定的回调函数,返回的是另一个Promise对象。这时,第二个then方法指定的回调函数,就会等待这个新的Promise对象状态发生变化。如果变为resolved,就调用funcA,如果状态变为rejected,就调用funcB。

catch方法

promise对象中,如果异步操作抛出错误,状态就会变为rejected,就会调用catch方法指定的回调函数处理这个错误,另外,then方法指定的回调函数,如果运行中抛出错误也会被catch方法捕获。例子:

p.then((val) = console.log('fulfilled:', val)) .catch((err) = console.log('rejected', err));// 等同于p.then((val) = console.log('fulfilled:', val)) .then(null, (err) = console.log("rejected:", err));

promise对象的错误具有“冒泡”性质,会一直向后传,直到被捕获,也就是说,会跳过中间的then函数例子:

 getJSON('/post/1.json').then(function(post) { return getJSON(post.commentURL);}).then(function(comments) { // some code}).catch(function(error) { // 处理前面三个Promise产生的错误});

finally方法

finally方法用于指定不管promise对象最后状态如何,都会执行的操作。例子

server.listen(port) .then(function () { // ... }) .finally(server.stop);

例子是服务器使用promise处理请求,然后使用finally()方法关掉服务器。

promise.all()方法

promise.all方法用于将多个promise实例,包装成一个新的promise实例。比如:const p = Promise.all([p1, p2, p3]);Promise.all方法,接受的是一个数组作为参数,其中的元素都是promise实例,如果不是,则会自动将参数转变为promie实例。p的状态是有它的数组里面的元素决定的,分两种状态(用上面举例)①只有p1 p2 p3的状态都变成fulfilled(已完成)的状态才会变成fulfilled(已完成),此时p1 p2 p3的返回值组成一个数组,传递给p的回调函数。②只有p1 p2 p3之中,有一个被rejucted(未完成),p的状态就会变成rejected(未完成),此时第一个被reject的实例的返回值,会传递给p的回调函数。例子:

const p1 = new Promise((resolve, reject) = {resolve('hello');}).then(result = result);const p2 = new Promise((resolve, reject) = {throw new Error('报错了');}).then(result = result);Promise.all([p1, p2]).then(result = console.log(result)).catch(e = console.log(e));// Error: 报错了enter code here

promise.race()方法

Promise.race方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例

const p = Promise.race([p1, p2, p3]);

如果p1 p2 p3不是promise实例,也会自动转变成promise实例与promise.all不同的是,上面代码中,只用p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

async函数是什么

async的引入,使得异步操作变得更加方便,那async函数是什么,其实它是Generator函数的语法糖。使异步函数、回调函数在语法上看上去更像同步函数。Generator这里就不介绍了。我们直接来学习async

async的基本用法

async返回值是一个promise对象,因此可以使用then方法添加回调函数,当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的内容。例子:

async function getStockPriceByName(name) { const symbol = await getStockSymbol(name); const stockPrice = await getStockPrice(symbol); return stockPrice;}getStockPriceByName('goog').then(function (result) { console.log(result);});

async函数的使用形式

//函数声明async function foo(){}//函数表达式const foo = async function(){};//对象的方法let obj = {async foo(){}};obj.foo().then(...)//class的方法class Storage{consttuctor(){ this.cachePromise=caches.open('avatars'); } async getAvatar(name){ const cache = await this.cachePromise; return cache.match('/avatars/${name}.jpg')}; }}const storage =new Storage();storage.getAvatar('jake').then(....);}}const storage =new Storage();storage.getAvatar('jake').then(...)//箭头函数const foo =async()={};

async 函数内部return语句返回的值,会成为then方法调用函数的参数。例子:

async function getTitle(url) { let response = await fetch(url); let html = await response.text(); return html.match(/title([sS]+)/title/i)[1];}getTitle('').then(console.log)// "ECMAScript 2017 Language Specification"

await 命令

正常情况下,await命令后面跟着的是一个promise对象,如果不是会自动转化为promise对象例子:

async function f(){return await 123;}f().then(v =console.log(v))//123

当一个await语句后面的promise变为reject,那么整个函数都会中断执行。例子:

async function f() { await Promise.reject('出错了'); await Promise.resolve('hello world'); // 不会执行}

错误处理

如果await 后面的异步操作有错,那么等同于async函数返回的promis对象被reject (上文讲promise对象的时候有提到过,冒泡性质) 例子:

async function f() { await new Promise(function (resolve, reject) { throw new Error('出错了'); });}f().then(v = console.log(v)).catch(e = console.log(e))// Error:出错了

使用try ....catch代码块课防止出错。例子:

async function f() { try { await new Promise(function (resolve, reject) { throw new Error('出错了'); }); } catch(e) { } return await('hello world');}

也可以将多个await命令都放在try..catch结构中

async function main() { try { const val1 = await firstStep(); const val2 = await secondStep(val1); const val3 = await thirdStep(val1, val2); console.log('Final: ', val3); } catch (err) { console.error(err); }}

注意点

①await命令只能用在async函数中,用在普通函数中会报错。

本文由澳门威斯尼人平台登录发布于Web前端,转载请注明出处:es6异步解决方案,解决异步编程的方法

相关阅读