最开始实现异步的方法:回调函数

method1(function(err, result) {
if (err) {
throw err;
}
method2(function(err, result) {
if (err) {
throw err;
}
method3(function(err, result) {
if (err) {
throw err;
}
method4(function(err, result) {
if (err) {
throw err;
}
method5(result);
});
});
});
});

回调地狱一层一层嵌套多个回调函数,会使代码错综复杂,难以理解和调试。

promise

promise是异步编程的一种解决方案,比传统的解决方案--回调函数和事件,更合理更强大。所谓promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,promise是一个对象,可以获取异步操作的消息,提供统一的API,各种异步操作都可以用同样的方法进行处理。

特点:1、对象状态不受外界影响。Promise 对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。

2、一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfiled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。如果改变已经发生了,你再对promise对象添加回调函数,也会立即得到这个结果。这与事件完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
有了promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,promise对象提供统一的借口,使得控制异步操作更加容易。
基本用法:
promise对象是一个构造函数,用来生成promise实例。
const promise = new Promise(function(resolve, reject) {
// ... some code if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
resolve和reject是两个函数,由javascript引擎提供,不用自己部署。
resolve函数作用:将promise对象的状态从未完成变为成功(即从pending变为resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去。
reject函数作用:将promise对象的状态从未完成变为失败(即从pending变为rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
Promise实例生成后用then方法分别指定resolved状态和rejected状态的回调函数。


promise.then(function(value){
// success
}, function(error){
// failure
})
// then方法的第二个参数可选,不一定要提供,
function timeout(ms){
return new Promise((resolve, reject) => {
setTimeout(resolve('done'), ms);
});
} timeout().then(function(value){
console.log(value);
}, function(error){
throw error;
})

如果调用resolve函数和reject函数时带有参数,那么它们的参数会被传递给回调函数。reject函数的参数通常是Error对象的实例,表示抛出的错误;resolve函数的参数除了正常的值外,还可能是另一个Promise实例。

const p1 = new Promise(function(resolve, reject){
setTimeout(() => reject(new Error('fail')), );
});
const p2 = new Promise(function(resolve, reject){
setTimeout(() => resolve(p1), );
});
p2.then(result => console.log(result)).catch(error => console.log(error));
// Error: fail
p1 是一个 Promise,3 秒之后变为 rejected。p2 的状态在 1 秒之后改变,resolve 方法返回的是 p1。由于 p2 返回的是另一个 Promise,导致 p2 自己的状态无效了,由 p1 的状态决定 p2 的状态。所以,后面的 then 语句都变成针对后者 p1。又过了 2 秒,p1 变为rejected,导致触发 catch 方法指定的回调函数。

注:调用resolve或reject并不会终结promise的参数函数的执行。

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

调用resolve(1)以后,后面的console.log(2)继续执行,并且会先打印出来,因为立即resolved的promise是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。一般来说,调用resolve或reject以后,promise的使命就完成了,后续操作应该放到then方法里面,而不应该直接写在resolve或reject后面,所以最好在它们前面加上return语句,这样就不会有意外。

new Promise((resolve, reject) => {
return resolve();
// 后面的语句不会执行
console.log();
})

finally()

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

promise
.then(result => {...})
.catch(error => {...})
.finally(() => {...});

响应多个promise

Promise.all()方法,接收单个可迭代对象(如数组)作为参数,并返回一个promise。这个可迭代对象的元素都是promise,只有在它们都完成后,所返回的promsie才会被完成。

let p1 = new Promise(function(resolve, reject) {
resolve();
});
let p2 = new Promise(function(resolve, reject) {
resolve();
});
let p3 = new Promise(function(resolve, reject) {
resolve();
});
let p4 = Promise.all([p1, p2, p3]);
p4.then(function(value) {
console.log(Array.isArray(value)); // true
console.log(value[]); //
console.log(value[]); //
console.log(value[]); //
});

Promise.race()方法:接收一个可迭代对象作为参数,并返回一个新的promise,一旦来源promise中有一个被解决,所返回的promise就会立刻被解决。

let p1 = Promise.resolve(); //等价于p1=new Promise(resolve => resolve(42));
let p2 = new Promise(function(resolve, reject) {
resolve();
});
let p3 = new Promise(function(resolve, reject) {
resolve();
});
let p4 = Promise.race([p1, p2, p3]);
p4.then(function(value) {
console.log(value); //
});

Promise缺点

1、无法取消Promise,一旦新建它就会立即执行,无法中途取消。

2、如果不设置回调函数,promise内部抛出的错误,不会反应到外部。

3、当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

async

async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。

async函数返回一个Promise对象,async函数内部return语句返回的值,会成为then方法回调函数的参数

async function f(){
return 'hello world';
}
f().then(v => console.log(v));
// "hello world"

async函数内部抛出的错误,会导致返回的promise对象变为reject状态。抛出的错误对象会被catch方法回调函数接收到。

async function f(){
throw new Error('出错了');
}
f().catch(e => console.log(e))
// Error:出错了
async 函数返回的 Promise 对象,必须等到内部所有 await 命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到 return 语句或者抛出错误。也就是说,只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。
async function asyncTest() {
let getUrl = await fetch();
console.log(getUrl);
let downloadUrl = await download();
console.log(downloadUrl);
return 'complete';
}
asyncTest().then(console.log) function fetch() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('fetchDone');
}, );
});
} function download() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('downloadDone');
}, );
});
}

上面代码模拟了一个抓取和一个下载,只有这两个操作全部完成,才会执行then方法里面的console.log

await

正常情况下,await命令后面是一个Promise对象,如果不是,会被转成一个立即resolve的Promise对象。

async function f(){
return await ; //await命令后面的参数是数值123,它被转成Promise对象,并立
// 即resolve
}
f().then(v => console.log(v))
//

await命令后面的promise对象如果变成reject状态,则reject的参数会被catch方法的回调函数接收到。

async function f(){
await Promise.reject('出错了');
}
f().then(v => console.log(v)).catch(e => console.log(e))
//出错了

注意上面代码中await语句前面没有return,但是reject方法的参数依然传入了catch方法的回调函数。如果在await前面加上return,效果一样。

只要一个await语句后面的Promise变为reject,那么整个async函数都会中断执行。

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

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

async function f(){
try {
await Promise.reject('出错了');
} catch(e){} return await Promise.resolve('hello world');
}
f().then(v => console.log(v));
// hello world

另一种方法是await后面的Promise对象再跟一个catch方法,处理前面可能出现的错误。

async function f(){
await Promise.reject("出错了")
.catch(e => console.log(e));
return await Promise.resolve('hello world');
}
f().then(v => console.log(v))
//出错了
// hello world

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

async function myFunction() {
try {
await somethingThatReturnsAPromise();
} catch (err) {
console.log(err);
}
} // 另一种写法 async function myFunction() {
await somethingThatReturnsAPromise()
.catch(function (err) {
console.log(err);
});
}

多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。

// 写法一
async function test() {
let [foo, bar] = await Promise.all([getFoo(), getBar()]);
} function getFoo() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('getFoo');
resolve()
}, );
})
} function getBar() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('getBar');
resolve()
}, );
})
} test() // 写法二
async function test() {
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;
}

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

async function test() {
let promises = [function1, function2, function3] promises.forEach(function (fun) {
const t = await fun();
console.log(t)
});
//Uncaught SyntaxError: await is only valid in async function
} function function1() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('function1')
}, )
})
} function function2() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('function2')
}, )
})
} function function3() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('function3')
}, )
})
} test()

如果将forEach方法的参数改成async函数,也有问题

promises.forEach(async function (fun) {
const t = await fun();
console.log(t)
});

上面代码可能不会正常工作,原因是这时三个异步操作将是并发执行,也就是同时执行,而不是继发执行。正确的写法是采用 for 循环。

for (let i of promises) {
const t = await i()
console.log(t)
}

如果希望多个请求并发执行,可以使用Promise.all方法,当三个请求都resolved时,下面两种写法效果相同。

async function test() {
let promises = [function1(), function2(), function3()]
let results = await Promise.all(promises);
console.log(results)
}

promise, async和await的更多相关文章

  1. ES系列之Promise async 和 await

    概述 promise是异步编程的一种解决方案,比传统的解决方案—回调函数和事件—更合理更强大. 所谓的promise就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作的结果). Pro ...

  2. promise以及async、await学习总结

    Promise/async.await帮我们解决了什么 它给我们提供了一种新的异步编程解决方案,同时避免了困扰已久的回调地狱 // 异步的处理可能会产生这样的回调地狱(第二个异步操作和第一个异步的结果 ...

  3. Promise,Async,await简介

    Promise 对象 转载:http://wiki.jikexueyuan.com/project/es6/promise.html 基本用法 ES6 原生提供了 Promise 对象.所谓 Prom ...

  4. promise async await使用

    1.Promise (名字含义:promise为承诺,表示其他手段无法改变) Promise 对象代表一个异步操作,其不受外界影响,有三种状态: Pending(进行中.未完成的) Resolved( ...

  5. ES 7 async/await Promise

    如何添加SSL证书实现https请求 https://blog.csdn.net/lupengfei1009/article/details/76828190/ ES 7     async/awai ...

  6. 详解promise、async和await的执行顺序

    1.题目和答案 一道题题目:下面这段promise.async和await代码,请问控制台打印的顺序? async function async1(){ console.log('async1 sta ...

  7. Promise、async、await在Egret的简单应用

    Egret Engnie 5.1.10 Egret Wing 4.1.5 一.Promise.async.await相关知识 Promise介绍 阮一峰 async函数 阮一峰 具体和详细的说明用法可 ...

  8. async和await对promise异步方案的改进,以及使用注意事项

    async.await相比原生promise的有优势: 1.更加简洁,await一个promise即可,那么会自动返回这个promise的resolve值,无需在then函数的回调中手动取值,彻底解决 ...

  9. promise、async和await

    async:async function 声明将定义一个返回 AsyncFunction 对象的异步函数.当调用一个 async 函数时,会返回一个 Promise 对象.当这个 async 函数返回 ...

随机推荐

  1. 初学Linux之标准I/O和管道

    标准输入和输出 程序是由指令+数据组成 程序的数据流有三种: 输入数据流:<–标准输入(stdin),一般默认是键盘 输出数据流:–>标准输出(stdout),一般默认到终端窗口 错误输出 ...

  2. JAVA导入支持类

    导入支持类(可以是JDK基础类或者自己编写的类),可以供本类调用方法和属性. java中import用法: 1.单类型导入(single-type-import),例如import java.io.F ...

  3. Mac下安装MySQL 5.6.40

    Mac下安装MySQL 5.6.40 - 干勾鱼的CSDN博客 - CSDN博客   原创 Mac下安装MySQL 5.6.40 2018-06-18 10:34:03 我是干勾鱼 阅读数 5927 ...

  4. @value取值

    配置文件的书写 valm.DlUrl=http://14.168.55.203:5199/FOSSecMngTemplate?wsdl vals.DlUrl=http://14.168.55.203: ...

  5. Centos7 系统更改apache默认网站目录(解决You don't have permission to access / on this server问题)

    当我们在Centos7中配置好Apache时,发现apache默认解析目录是在 /var/www/html,也就是说当访问服务器 IP 或者本地 localhost 时, 默认定位到这个目录里的 in ...

  6. 4.git的基本命令

    版本库 index 暂存区,HEAD 将来1.0,2.0的指向  多次add,一次commit 每次commit一次,head就指向了最新的版本.head是回退版本的时候会用到 一般有开发的分支,ma ...

  7. Hadoop 部署之环境准备(一)

    目录 一.软硬件规划 二.主机名解析 三.配置 SSH 互信 四.创建用户 五.JDK 的安装 一.软硬件规划 ID 主机类型 主机名 IP 应用软件 操作系统 硬件配置 1 物理机 namenode ...

  8. 安装mysqlmysql-5.7.24-linux-glibc2.12-x86_64

    1.下载mysql-5.7.24-linux-glibc2.12-x86_64.tar.gz(/opt目录) 2.tar -zxvf mysql-5.7.24-linux-glibc2.12-x86_ ...

  9. 【并行计算-CUDA开发】 NVIDIA Jetson TX1

    概述 NVIDIA Jetson TX1是计算机视觉系统的SoM(system-on-module)解决方案.它组合了最新的NVIDIAMaxwell GPU架构,其具有ARM Cortex-A57 ...

  10. SpringEl表达式解析

    应用场景: 1.用户日志 2.缓存处理 3........... import org.springframework.expression.EvaluationContext; import org ...