es6在原生代码的用法_【es6】js原生的promise

本文深入探讨了JavaScript中Promise的使用,如何解决事件监听的不足,通过Promise实现异步操作的管理和回调。文章详细介绍了Promise的特性,如状态不可变、链式调用,并通过实例展示了如何用Promise处理图片加载、Ajax请求等异步操作,以及如何通过Promise.all处理并发和串行任务。此外,还提到了Promise的错误处理和在实际应用中的优势。
摘要由CSDN通过智能技术生成

JavaScript 是单线程的,这意味着任何两句代码都不能同时运行,它们得一个接一个来。在浏览器中,JavaScript 和其他任务共享一个线程,不同的浏览器略有差异,但大体上这些和 JavaScript 共享线程的任务包括重绘、更新样式、用户交互等,所有这些任务操作都会阻塞其他任务。

一、事件的不足

对于那些执行时间很长,并且长时间占用线程的代码,我们通常使用异步来执行,但是又如何判断其是否执行完毕或者失败呢?我们通常使用事件监听,但事件监听只能监听绑定之后发生的事件,但有可能你写绑定事件代码之前该事件就已经发生,这样你就无法检测。下面进行说明:

你应该会用事件加回调的办法来处理这类情况:

var img1 = document.querySelector('.img-1');

img1.addEventListener('load', function() {//啊哈图片加载完成

});

img1.addEventListener('error', function() {//哎哟出问题了

});

这样加载图片就不会占据线程。我们添加几个监听函数,请求图片,然后 JavaScript 就停止运行了,直到触发某个监听函数。

上面的例子中唯一的问题是,事件有可能在我们绑定监听器之前就已经发生,所以我们先要检查图片的“complete”属性:

var img1 = document.querySelector('.img-1');functionloaded() {//啊哈图片加载完成

}if(img1.complete) {

loaded();

}else{

img1.addEventListener('load', loaded);

}

img1.addEventListener('error', function() {//哎哟出问题了

});

这样还不够,如果在添加监听函数之前图片加载发生错误,我们的监听函数还是白费,不幸的是 DOM 也没有为这个需求提供解决办法。而且,这还只是处理一张图片的情况,如果有一堆图片要处理那就更麻烦了。

事件不是万金油

事件机制最适合处理同一个对象上反复发生的事情—— keyup、touchstart 等等。你不需要考虑当绑定监听器之前所发生的事情,当碰到异步请求成功/失败的时候,你想要的通常是这样:

img1.callThisIfLoadedOrWhenLoaded(function() {//加载完成

}).orIfFailedCallThis(function() {//加载失败

});//以及……

whenAllTheseHaveLoaded([img1, img2]).callThis(function() {//全部加载完成

}).orIfSomeFailedCallThis(function() {//一个或多个加载失败

});

这就是 Promise。如果 HTML 图片元素有一个“ready()”方法的话,我们就可以这样:

img1.ready().then(function() {//加载完成

}, function() {//加载失败

});//以及……

Promise.all([img1.ready(), img2.ready()]).then(function() {//全部加载完成

}, function() {//一个或多个加载失败

});

基本上 Promise 还是有点像事件回调的,除了:

一个 Promise 只能成功或失败一次,并且状态无法改变(不能从成功变为失败,反之亦然)

如果一个 Promise 成功或者失败之后,你为其添加针对成功/失败的回调,则相应的回调函数会立即执行

这些特性非常适合处理异步操作的成功/失败情景,你无需再担心事件发生的时间点,而只需对其做出响应。

二、promise使回调函数和异步操作彻底分离

看了上述所讲,感觉promise和回调函数作用差不多,但对于多层嵌套的回调,在代码组织上确实优雅很多。

网页的交互越来越复杂,JavaScript 的异步操作也随之越来越多。如常见的 ajax 请求,需要在请求完成时响应操作,请求通常是异步的,请求的过程中用户还能进行其他的操作,不会对页面进行阻塞,这种异步的交互效果对用户来说是挺有友好的。但是对于开发者来说,要大量处理这种操作,就很不友好了。异步请求完成的操作必须预先定义在回调函数中,等到请求完成就必须调用这个函数。这种非线性的异步编程方式会让开发者很不适应,同时也带来了诸多的不便,增加了代码的耦合度和复杂性,代码的组织上也会很不优雅,大大降低了代码的可维护性。情况再复杂点,如果一个操作要等到多个异步 ajax 请求的完成才能进行,就会出现回调函数嵌套的情况,如果需要嵌套好几层,那你就只能自求多福了。

先看看下面这个常见的异步函数。

var showMsg = function(){

setTimeout(function(){

alert( ‘hello’ );

}, 5000 );

};

如果要给该函数添加回调,通常会这么干。

var showMsg = function( callback ){

setTimeout(function(){

alert( ‘hello’ );

// 此处添加回调

callback();

}, 5000 );

};

如果是使用 easy.js 的 Promise,添加回调的方法就会优雅多了,前提是需要将原函数封装成一个 promise 实例。

var showMsg = function(){

// 构造promise实例

var promise = new E.Promise();

setTimeout(function(){

alert( ‘hello’ );

// 改变promise的状态

promise.resolve( ‘done’ );

}, 5000 );

// 返回promise实例

return promise;

};

将一个普通的函数封装成一个 promise 实例,有3个关键步骤,第一步是在函数内部构造一个 promise 实例,第二步是部署函数执行完去改变 promise 的状态为已完成,第三步就是返回这个 promise 实例。每个 promise 实例都有3种状态,分别为 pending(未完成)、resolved(已完成,成功)、rejected(已拒绝,失败)。下面再来看看如何添加回调。

showMsg().then(function( str ){

// 回调添加到这里来了

callback( str );

});

这样就将回调函数和原来的异步函数彻底的分离了,从代码组织上看,优雅了很多。resolve 接受一个参数,该参数就可以轻松实现将数据传送给使用 then 方法添加的回调中。

对于 ajax 请求,easy.js 直接将 ajax 方法封装成了 promise 对象,可以直接添加 then 方法来回调。

E.ajax({

url : ‘test1.php’,

type : ‘GET’

})

then(function(){

// 添加请求成功的回调

}, function(){

// 添加请求失败的回调

});

then 方法接受2个函数作为参数,第一个函数是已完成的回调,第二个就是已失败的回调。

如果有上面提到的多个 ajax 请求的情况呢?那么就要用到 when 这个方法了。该方法可以接受多个 promise 实例作为参数。

var requests = E.when(E.ajax({

url : ‘test1.php’,

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值