ES6--Promise、Generator及async
来源:互联网 发布:注册淘宝账号会员名字 编辑:程序博客网 时间:2024/05/17 08:20
ES6诞生以前,异步编程的方法,大概有如下四种:回调函数、事件监听、发布/订阅、Promise对象;ES6中,引入了Generator函数;ES7中,async更是将异步编程带入了一个全新的阶段。
十四、Promise对象
Promise,就是一个对象,用来传递异步操作的消息,避免了层层嵌套的回调函数。它代表了某个未来才会知道结果的事件(通常是一个异步操作),并且这个事件提供统一的API,可供进一步处理。
(1)对象的状态不受外界影响。有三种状态:Pending(进行中)、Resolved(已完成,又称Fulfilled)和Rejected(已失败)。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从Pending变为Resolved和从Pending变为Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。
缺点:
- 无法取消Promise,一旦新建它就会执行,无法中途取消
- 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部
- 当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
更多Promise请参考:http://blog.csdn.net/ligang2585116/article/details/51417334
十五、Generator函数
从计算机角度看,生成器是一种类协程或半协程,它提供了一种可以通过特定语句或方法使其执行对象暂停的功能。
Generator函数,返回一个部署了Iterator接口的遍历器对象,用来操作内部指针。以后,每次调用遍历器对象的next方法,就会返回一个有着value和done两个属性的对象。value属性表示当前的内部状态的值,是yield语句后面那个表达式的值;done属性是一个布尔值,表示是否遍历结束。
yield [[expression]]
yield 关键字使生成器函数暂停执行,并返回跟在它后面的表达式的当前值。可以把它想成是return关键字的一个基于生成器的版本,但其并非退出函数体,而是切出当前函数的运行时,与此同时可以将一个值带到主线程中。yield语句是暂停执行的标记,而next方法可以恢复执行。
function* gen(){ yield 'li'; yield 'gang'; // 有误!!! return '!';}var g = gen();g.next(); // {value: 'li', done: false}g.next(); // {value: 'gang', done: false}g.next(); // {value: '!', done: true}
(1)遇到yield语句,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值;
(2)下一次调用next方法时,再继续往下执行,直到遇到下一个yield语句;
(3)如果没有再遇到新的yield语句,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值;
(4)如果该函数没有return语句,则返回的对象的value属性值为undefined。
需要注意的是,yield语句后面的表达式,只有当调用next方法、内部指针指向该语句时才会执行,因此等于为JavaScript提供了手动的“惰性求值”(Lazy Evaluation)的语法功能。
function* gen() { yield 123 + 456;}
上述示例中,yield后面的表达式123 + 456,不会立即求值,只会在next方法将指针移到这一句时,才会求值。Generator函数也可以不用yield语句,这时就变成了一个单纯的暂缓执行函数。
function* f() { console.log('执行了!')}let gen = f();setTimeout(function () { gen.next()}, 2000);
next方法的参数
注意: yield句本身没有返回值(返回undefined)。next方法可以带一个参数,该参数就会被当作上一个yield语句的返回值。
function* foo(x) { var y = 2 * (yield (x + 1)); var z = yield (y / 3); return (x + y + z);}var a = foo(5);a.next(); // Object{value:6, done:false}a.next(); // Object{value:NaN, done:false}a.next(); // Object{value:NaN, done:true}var b = foo(5);b.next(); // { value:6, done:false }b.next(12); // { value:8, done:false }b.next(13); // { value:42, done:true }
next方法不带参数,导致y的值等于2 * undefined
(即NaN),除以3以后还是NaN;next方法提供参数,第一次调用b的next方法时,返回x+1的值6;第二次调用next方法,将上一次yield语句的值设为12,因此y等于24,返回y/3的值8。
注意:这个功能有很重要的语法意义。Generator函数从暂停状态到恢复运行,它的上下文状态(context)是不变的。通过next方法的参数,就有办法在Generator函数开始运行之后,继续向函数体内部注入值。也就是说,可以在Generator函数运行的不同阶段,从外部向内部注入不同的值,从而调整函数行为。
function* f() { for(let i=0; true; i++) { let reset = yield i; if(reset) { i = -1; } }}let g = f();g.next() // { value: 0, done: false }g.next() // { value: 1, done: false }g.next(true) // { value: 0, done: false }
for…of循环
for...of
循环可以自动遍历Generator函数时生成的Iterator对象,且此时不再需要调用next方法。
function *foo() { yield 1; yield 2; return 3;}for (let v of foo()) { console.log(v);}
利用Generator函数和for...of
循环,实现斐波那契数列
function* fibonacci() { let [prev, curr] = [0, 1]; while (true) { [prev, curr] = [curr, prev + curr]; yield curr; }}for (let n of fibonacci()) { if (n > 1000) break; console.log(n);}
yield* [[expression]]
yield*
一个可迭代对象,就相当于把这个可迭代对象的所有迭代值分次 yield 出去。表达式本身的值就是当前可迭代对象迭代完毕(当done为true时)时的返回值。
function* gen(){ yield [1, 2]; yield* [3, 4];}var g = gen();g.next(); // {value: Array[2], done: false}g.next(); // {value: 3, done: false}g.next(); // {value: 4, done: false}g.next(); // {value: undefined, done: true}
判断是否为Generator函数
function isGenerator(fn){ // 生成器示例必带@@toStringTag属性 if(Symbol && Symbol.toStringTag) { return fn[Symbol.toStringTag] === 'GeneratorFunction'; }}
十六、async函数
async函数可以理解为Generator函数的语法糖,使用async内置了执行器,无需调用next方法进行逐步调用。且其返回值为Promise。
基本用法
async
函数返回一个 Promise 对象,可以使用then
方法添加回调函数。当函数执行的时候,一旦遇到await
就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
async function gen(x){ var y = await x + 2; var z = await y + 2; return z;}gen(1).then(result => console.log(result), error => console.log(error));gen(1).then(result => console.log(result)).catch(error => console.log(error));
5秒以后,输出hello world
/*回调方式*/function test(callback) { setTimeout(() => callback('hello world'), 5000);}var res = test((value) => console.log(value));console.log(res);/*Promise方式*/function test() { return new Promise((resolve, reject) => { setTimeout(() => { return resolve('hello world'); }, 5000) });}test().then((value) => console.log(value));/*async方式*/async function test() { return await new Promise((resolve, reject) => { setTimeout(() => { return resolve('hello world'); }, 5000) });}test().then((value) => console.log(value));
await命令
正常情况下,await命令后是一个Promise对象。如果不是,会被转成一个立即resolve的Promise对象。
/*成功情况*/async function f() { return await 123;}f().then(value => console.log(value)); // 123/*失败情况*/async function f() { return Promise.reject('error');}f().catch(e => console.error(e)); // error
错误处理
async function f() { await new Promise((resolve, reject) => { throw new Error('出错了'); })}f().then(v => console.log(v)) .catch(e => console.error(e)); // Error: 出错了
注意点
await只能用在async函数中,不能用在普通函数中
/* 错误处理 */function f(db) { let docs = [1, 2, 3]; for(let doc of docs) { await db.push(doc); } return db; // Uncaught SyntaxError: Unexpected identifier}/* 正确处理(顺序执行) */async function f(db) { let docs = [1, 2, 3]; for(let doc of docs) { await db.push(doc); } return db;}let ary = [];f(ary);console.log(ary); // [1, 2, 3]/* 正确处理(并发执行) */async function f(db) { let docs = [1, 2, 3]; let promises = docs.map(doc => db.push(doc)); db = await Promise.all(promises); return db;}let ary = [];f(ary);console.log(ary); // [1, 2, 3]
await后面可能存在reject,需要进行try…catch代码块中
async function f() { try { await Promise.reject('出错了'); } catch(e) { console.error(e); } return Promise.resolve('hello');}f().then(v => console.log(v)); // 出错了 hello
多个异步操作,如果没有继承关系,最好同时触发
async function f() { let [foo, bar] = await Promise.all([getFoo(), getBar()]); return [foo, bar];}
十七、Promise和async使用场景
下述描述的使用场景,只是自己在开发中经常遇到的,并不一定完全符合所有人的使用,只是这样用起来会很便利和实现一些比较难处理的情况。
一个过程中同时存在异步、同步情况,请使用Promise
/*常规方式,错误!不能实现*/function test(bool) { // bool为true,直接返回"hello" // bool为false,进行异步请求,这里使用setTimeout代替异步过程 if(bool) { return "hello"; } else { setTimeout(() => { return "world"; }, 5000); }}test(true); // "hello"test(false); // 无任何输出内容/*Promise正确方式*/function test(bool) { // bool为true,直接返回"hello" // bool为false,进行异步请求,这里使用setTimeout代替异步过程 return new Promise((resolve, reject) => { if(bool) { return resolve("hello"); } else { setTimeout(() => { return resolve("world"); }, 5000); } });}test(true).then(v => console.log(v)); // 'hello'test(false).then(v => console.log(v)); // 大约5s后输出 'world'
包裹本身不支持async的函数,且hold住当前请求
import fs from "fs";async function readFile(filepath) { return await new Promise((resolve, reject) => { fs.stat(filepath, (error) => { if(error) { return reject("文件不存在!"); } let content = fs.readFileSync(filepath, "utf8"); return resolve(content); }) })}// 测试readFile(__filename).then((content) => { console.log(content)}).catch((error) => { console.error(error);});
- ES6--Promise、Generator及async
- ES6总结--Promise 、Generator 、Async/Await
- generator async promise 缕一缕。
- es6的Promise及es7的Async/Await应用
- 异步 promise +generator+async(未完成)
- 用 ES6 generator & Promise 写异步代码
- ES6-Generator函数和async函数
- Callback Promise Generator Async-Await 和异常处理的演进
- ECMAScript 6 入门笔记(五)异步promise,Generator,async
- Callback Promise Generator Async-Await 和异常处理的演进
- 关于Promise,Generator,async / await 对异步的处理
- ES6学习笔记(七)--Generator函数与Promise对象
- co核心代码剖析--promise与ES6 generator结合
- 5、ES6 === 异步 Promise Generator yield
- ES6--Promise
- ES6 Promise
- ES6-Promise
- ES6 Promise
- AngularJS中星级的评价(ionic)
- 什么才是动力电池管理系统(BMS)的核心技术?
- JAXB将JAVA对象转换为XML时CDATA的问题
- 驱动程序调试(二)————根据内核打印的段错误信息分析
- html()、text()、val()方法区别
- ES6--Promise、Generator及async
- FTP文件传输协议详解
- Eureka与ZooKeeper 的比较
- Pixhawk-飞控平台
- 读取word模板,并写入数据到word文件中
- 64位CentOS 6.7安装Caffe (非GPU模式 )
- window+curl+elasticsearch
- 智力题
- 解决 Android Studio 乱码问题