【ES6】Promise、Generator和Async

Promise对象

Promise ,简单来说就是 个容器,里面保存着某个未来才会结束的事件(通常是异步操作)的结果。

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

有以下两个特点

  • 对象的状态不受外界影响。

有 3种状态: Pending (进行中)、 Fulfilled (己成功)和Rejected (己失败)。只有异步操作的结果可以决定当前是哪状态,任何其他操作都无法改变这个状态。这也是“Promise ”这个名字的由来,它在英语中意思就是“承诺”,表示其他手段无法改变。

  • 一旦状态改变就不会再变,任何时候都可以得到这个结果。

有了 Promise 对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数,避免回调地狱。

Promise 也有 些缺点。首先,无法取消 Promise 旦新建它就会立即执行,无法中途取
消。其次,如果不设置回调函数, Promise 内部抛出的错误不会反应到外部 再者,当处于 Pending
状态时,无法得知目前进展到哪 个阶段(刚刚开始还是即将完成)。

基本用法

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

Promise 实例生成以后 ,可以用 then 方法分别指 Resolved 态和 Rejected 态的回调函数。

Promise 实例具有 then 方法,即 then 方法是定义在原型对象 Promise .prototype
它 的作用是为 Promise 实例添加状态改变时的回调函数

Promise.all()

Promise all 方法用于将多个 Promis 实例包装成 个新的 Promi 实例。

var p = Promise.all ([pl , p2 , p3)) ;

只有 pl p2 抖的状态都变成 Fulfilled 的状态才会变成 Fulfilled ,此 pl p2
p3 的返回值组成 个数组,传递给 的回调函数。

只要 pl p2 p3 中有 个被 ected 的状态就变成 Rejected 此时第一个被 ected的实例的返回值会传递给 的回调函数。

//生成一个 Promise 对象的数纽
var promises = [2 , 3 , 5 , 7 , 11 , 13) .map (function (id) { 
return getJSON (I post/+ id +. json” ) ; 
} ) ., 
Promise.all(promises) . then(function (posts) { 
// 
}) . catch(function(reason) { 
// 
}) ;

Promise.race()

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

var p = Promise.race ([pl , p2 , p3]) ; 

上面的代码中,只要 pL p2, p3 中有 个实例率先改变状态, 的状态就跟着改变。那个率先改变的 Promise 实例的返回值就传递给 的回调函数。

done()
无论 Promise 对象的回调链以 then 方法还是 catch 方法结尾,只要最后一个方法抛出错误, 都有可能无法捕捉到(因为 Promise 内部的错误不会冒泡到全局)。为此,我们可以提供done 方法,它总是处于回调链的尾端,保证抛出任何可能出现的错误。

finally()
finally 方法用于指定不管 Promise 象最后状态如何都会执行的操作。它与 done 方法的最大区别在于,它接受 一个普通的回调函数作为参数,该函数不管怎样都必须执行

Promise应用

加载图片

const preloadimage = function (path) { 
return new Promise(function (resolve , reject) { 
var image= new Image() ; 
image . onload = resolve;
image.onerror = reject;
image.src = path;

Generator 函数

基本概念

是 ES6 提供的 种异步编程解决方案,语法行为与传统函数完全不同.

从语法上,首先可以把它理解成 个状态机,封装了多个内部状态。

执行 Generator 函数会返回个遍历器对象 也就是说, Generator 函数除了是状态机,还是个遍历器对象生成函数 返回的遍历器对象可以依次遍历 Generator 函数内部的每 个状态。

Generator的特点:

  • function 命令与函数名之间有 个星号:
  • 函数体内部使用 yield 吾句定义不同的内部状态(“ yield ”在英语里的
    意思就是产出。
function* helloWorldGenerator() { 
yield ’ hello ’; 
yield ’world ’; 
return ’ ending ’;
}
var hw = helloWorldGenerator() ;

上面的代码定义了 Generator 函数一 helloWorldGenerator 部有两
yield 语句“ hello ”和“ world ”,即该函数有 3个状态 hello world return 语句(结束执行)不同的是调用 Gen rator 函数后,该函数并不执行 返回的 不是函数运行结果 而是 个指 向内部状态的的指针对象,

Generator函数返回的是一个遍历器对象,所以下一步必须调用遍历器对象的next方法,使得指针移向下一个状态。

也就是说,每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,知道遇到下一条yield或return语句为止。

以后,每次调用遍历器对象的 next 方法,就会返回 个有着 value done 两个属性的对象value 属性表示当前的内部状态的值,是 yield 语句后面那个表达式的值 done 属性是布尔值,表示是否遍历结束

由于 Generator 函数返回的遍历器对象只有调用 next 方法才会遍历下 个内部状态,所以其实提供了一 种可以暂停执行的函数 ield 语句就是暂停标志。

  • 正常函数只能返回 个值,因为只能执一次return 语句

  • Generator 函数可以返回 系列的值,因为可以有任意多条 yield 语句

yield 表达式只能用在 Generator 函数里面,用在其他地方都会报错

for … . of 循环可以自动遍历 Generator 函数生成的 Iterator 对象,且此时不再需要调next 方法。

function *foo() { 
yield l ; 
yield 2 ; 
yield 3 ; 
yield 4; 
yield 5; 
return 6; 
}
for (let v of foo ()) { 
console.log (v); 
}
// 1 2 3 4 5

Generator 函数 this

总是返回 个遍历器 ES6 规定这个遍历器是 nerator 函数的实 ,它也
继承了 nerator 函数的 prototype 对象上的方法。

Generator 函数也不能j~ new 命令 起用,否则会报错。

Generator 是实现状态机的最佳, 比如,下面的 clock 函数就是一个状态机

var ticking = true ; 
var clock= function () { 
if (ticking) 
console . log (’ Tick !) ; 
else 
console. log (’ Tock !); 
ticking = !ticking;
}

如果用Generator函数来写

var clock = function* () { 
while (true ) { 
console . log ( ’ Tick 1);
yield; 
console.log (’ Tock !); 
yield;
}
};

Generator 可以暂停函数执行,返回任意表达式的值。这种特点使得 Generator 多种应用场景。

异步操作的同步化表达

Generator 函数的暂停执行效果,意味着可以把异步操作写在yield 语句里面,等到调用next 方法时再往后执行.

这实际上等同于不需要写回调函数了,因为异步操作的后续操作可
以放在 yield 语句下面,反正要等到调用 next 方法时再执行。所以, Generator 函数的一个重要实际意义就是用于处理异步操作,改写回调函数。

AJAX 是典型的异步操作,通过 Generator 函数部署 AJAX 操作,可以用同步的方式表达

function* main () { 
var result= yield request (” http://some.url”); 
var resp= JSON.parse(result); 
console.log(resp.value) ;
}

function request(url) { 
makeAjaxCall(url, function(response) { 
it.next(response);
});
}

var it = main(); 
it.next() ;

Generator 函数的异步应用

异步编程对 JavaScript 来说非常重要。 Javascript 的执行环境是“单线程”的,如果没有异步编程,根本无法使用,不然会造成卡死。

es6诞生之前,异步编程方法大概以下四种:

  • 回调函数
  • 事件监听
  • 发布/订阅
  • Promise对象

Generator 函数将 JavaScript 异步编程带入了 个全新的阶段。

Promise 对象就是为了解决这个问题而被提出的。它不是新的语法功能,而是一种新的写法,允许将回调函数的嵌套改写成链式调用。

Pro ise 的最大问题是代码冗余,原来的任务被 Promi 包装之后,无论什么操作,一眼看去都是许多 then 的堆积,原来的语义变得很不清楚。

Generator 函数是协程在 ES6 中的实现,最大特点就是可以交出函数的执行权(即暂停执行)。

异步任务的封装

Thunk 函数是自动执行 Generator 函数的 种方法。

Async函数

sync 函数是什么 ?用一句话来说,它就是 Generator 函数的语法糖

通过比较就会发现, async 函数就是将 Generato 函数的星号(*替换成 async ,将 yield替换成 await ,仅此而己。

改进体现在以下四点:

  • 内置执行器
    Generator 函数的执行必须靠执行器,所以才有了 模块,而 asy 函数自带执行器。也就是说, sync 函数的执行与普通函数一样,只要一行。asyncReadFile();
    上面的代码调用了 asyncReadFile 函数 然后它就会自动执行,输出最终的结果。这完全不像 Generator 函数需要调用 next 方法或者使用 模块才能真正执行并得到最终结果。

  • 更好的语义

async await 比起星号和 yield ,语义更清楚了。 async 表示函数里有异步操作,await 表示紧跟在后面的表达式需要等待结果。

  • 更广的适用性
  • 返回值是 Promise

asyηc 函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便了许多。可以用 then 方法指定下一步的操作。
步说, async 函数完全可以看作由多个异步操作包装成的 Promise 对象,而 await命令就是内部 then 命令的语法糖。

用法

async 函数的语法规则总体上来说比较简单,难点是错误处理机制。

async 函数返回 Pro ise 象。

也就是说 只有 async 函数内部的异步操作执行完,才会执行 then 方法指定的回调函数。

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

async 函数的实现原理,

Generator 函数和自动执行器包装在一 个函数里。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值