浅谈JavaScript中promise的使用

阅读目录

  • 什么是Prmoise
  • Promise的使用

最近在看《你不知道的javascript中卷》,发觉作者花了基本一半的篇幅去讲异步和promise,觉得有必要总结一下。

其实本文的目的是想手写一个Promise的,无奈总结着总结着发觉篇幅有点长,因此只好一分为二,先介绍promise的用法,知道怎么用,我们才知道怎么写,所以把手写一个promise的任务放到了下一篇文章当中。

当然,网上有很多关于promise的文章,都可以参考参考,有误之处,欢迎之处。

什么是Prmoise

promise是ES6新增的一个特征,它已被列入ES6的正式规范中

Promise对象可以理解为一次执行的异步操作,使用promise对象之后可以使用一种链式调用的方式来组织代码;让代码更加的直观。也就是说,有了Promise对象,就可以将异步操作以同步的操作的流程表达出来,避免了层层嵌套的回调函数。

示例:未使用promise,回调必须层层嵌套

$.ajax(url1, function(data1){
 // do something...
 $.ajax(url2, function(data2){
 // do something...
 $.ajax(url3, function(data3){
 // do something...
 done(data3); // 返回数据
 })
 });
});

如果有多个嵌套,导致代码不够直观,而且如果几个操作之前没有前后顺序之分,需要等待上一个操作完成才可以进行下一个操作,造成不必要的等待

promise就是为了解决这些问题而产生的。

Promise对象的特点:

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

Promise对象代表一个异步操作,有三种状态

  • pending(执行中)
  • Resolved(成功,又称Fulfilled)
  • rejected(拒绝)

其中pending为初始状态,fulfilled和rejected为结束状态(结束状态表示promise的生命周期已结束)。

promise只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态.。

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

Promise对象的状态改变,只有两种可能:从Pending变为Resolved和从Pending变为Rejected

pending->fulfilled,pending->rejected。

只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果

Promise对象的缺点:

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

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

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

promise兼容性

除了IE这种古老的浏览器和一些低版本的安卓外,现代浏览器支持还是挺好的,所以我们可以在谷歌的控制台直接测试我们的代码

Promise的使用

先提前说明一下,下面的代码示例,都可以复制到谷歌的控制台就行测试!!

1、基本用法:

(1)、首先我们new一个Promise,将Promise实例化

(2)、然后在实例化的promise可以传两个参数,一个是成功之后的resolve,一个是失败之后的reject

(3)、Promise实例生成以后,可以用then方法分别指定Resolved状态和Reject状态的回调函数

代码如下:

var promise = function(isReady){
 return new Promise(function(resolve, reject){
 // do somthing, maybe async
 if (isReady){
  return resolve('hello world');
 } else {
  return reject('failure');
 }
 });
}
//Promise实例生成以后,可以用then方法分别指定Resolved状态和Reject状态的回调函数。
promise(true).then(function(value){
 // success,这里是resolve的回调函数
 console.log(value); //hello world
}, function(err){
 // failure,这里是reject的回调函数
 console.log(err)
})

上述代码是执行成功,返回hello world,如果想测试一下失败后的返回值,可以在promise(true).then...这里改为 promise(false).then...即可

2、链式操作

也许你会说,Promise只是简化层层回调的写法而已吧,其实不然,它的精髓是通过维护状态、传递状态的方式来使回调方式能够及时的调用,因此,相比于callback,它更灵活,更简单。下面我们来看看Promise的链式操作:

makePromise1()
.then(function(value){
 console.log(value);
 return makePromise2();
})
.then(function(value){
 console.log(value);
 return makePromise3();
})
.then(function(value){
 console.log(value);
});
function makePromise1(){
 var p = new Promise(function(resolve, reject){
 //异步操作
 setTimeout(function(){
  console.log('异步任务1');
  resolve('异步任务1传过来的值');
 }, 2000);
 });
 return p;
}
function makePromise2(){
 var p = new Promise(function(resolve, reject){
 //异步操作
 setTimeout(function(){
  console.log('异步任务2');
  resolve('异步任务2传过来的值');
 }, 2000);
 });
 return p;
}
function makePromise3(){
 var p = new Promise(function(resolve, reject){
 //异步操作
 setTimeout(function(){
  console.log('异步任务3');
  resolve('异步任务3传过来的值');
 }, 2000);
 });
 return p;
}

上面的代码中,我们有三个异步操作,makePromise1,makePromise2,makePromise3。其中第二个和第三个依次执行,也就是上一个操作完成之后才可以进行。

输出的值为:

异步任务1
异步任务1传过来的值
异步任务2
异步任务2传过来的值
异步任务3
异步任务3传过来的值

3、Promise的catch方法

var promise = function(isReady){
 return new Promise(function(resolve, reject){
 // do somthing, maybe async
 if (isReady){
  return resolve('hello world');
 } else {
  return reject('failure');
 }
 });
}
promise(true)
.then(function(value){
 console.log('resolved');
 console.log(value);
 console.log(haha); //此处的haha未定义
})
.catch(function(error){
 console.log('rejected');
 console.log(error);
});

catch 方法是 then(onFulfilled, onRejected) 方法当中 onRejected 函数的一个简单的写法,也就是说可以写成 then(fn).catch(fn),相当于 then(fn).then(null, fn)

使用 catch 的写法比一般的写法更加清晰明确,其实可以类比成try/catch,这样,其中有报错的地方不会阻塞运行。比如定义了一个未定义haha,正常来说它上面的代码也不会运行,因为被这个报错阻塞了,有了catch,它上面的代码可以正常运行下去:

控制台打印出来的东西:

resolved
hello world
rejected
ReferenceError: haha is not defined(…)

4、promise.all方法

Promise.all 可以接收一个元素为 Promise 对象的数组作为参数,当这个数组里面所有的 Promise 对象都变为 resolve 时,该方法才会返回。

代码示例:

var p1 = new Promise(function (resolve) {
 setTimeout(function () {
 resolve("第一个promise");
 }, 3000);
});
var p2 = new Promise(function (resolve) {
 setTimeout(function () {
 resolve("第二个promise");
 }, 1000);
});
Promise.all([p1, p2]).then(function (result) {
 console.log(result); // ["第一个promise", "第二个promise"]
});

上面的代码中,all接收一个数组作为参数,p1,p2是并行执行的,等两个都执行完了,才会进入到then,all会把所有的结果放到一个数组中返回,所以我们打印出我们的结果为一个数组。

值得注意的是,虽然p2的执行顺序比p1快,但是all会按照参数里面的数组顺序来返回结果。all的使用场景类似于,玩游戏的时候,需要提前将游戏需要的资源提前准备好,才进行页面的初始化。

5、promise.race方法

race的中文意思为赛跑,也就是说,看谁跑的快,跑的快的就赢了。因此,promise.race也是传入一个数组,但是与promise.all不同的是,race只返回跑的快的值,也就是说result返回比较快执行的那个。

var p1 = new Promise(function (resolve) {
 setTimeout(function () {
 console.log(1);
 resolve("第一个promise");
 }, 3000);
});
var p2 = new Promise(function (resolve) {
 setTimeout(function () {
 console.log(2);
 resolve("第二个promise");
 }, 1000);
});
Promise.race([p1, p2]).then(function (result) {
 console.log(result);
});
// 结果:
// 2
// 第二个promise
// 1

可以看到,传的值中,只有p2的返回了,但是p1没有停止,依然有执行。

race的应用场景为,比如我们可以设置为网路请求超时。写两个promise,如果在一定的时间内如果成功的那个我们没有执行到,我们就执行失败的那个,这里不再举例子,可以看看阮一峰的ES入门。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持我们!

(0)

相关推荐

  • 详解Javacript和AngularJS中的Promises

    比如页面调用google地图的api时就使用到了promise. function success(position){ var cords = position.coords; console.log(coords.latitude + coords.longitude); } function error(err){ console.warn(err.code+err.message) } navigator.geolocation.getCurrentPosition(success, e

  • NodeJS中利用Promise来封装异步函数

    在写Node.js的过程中,连续的IO操作可能会导致"金字塔噩梦",回调函数的多重嵌套让代码变的难以维护,利用CommonJs的Promise来封装异步函数,使用统一的链式API来摆脱多重回调的噩梦. Node.js提供的非阻塞IO模型允许我们利用回调函数的方式处理IO操作,但是当需要连续的IO操作时,你的回调函数会多重嵌套,代码很不美观,而且不易维护,而且可能会有许多错误处理的重复代码,也就是所谓的"Pyramid of Doom". 复制代码 代码如下: ste

  • Javascript中的神器——Promise

    Promise in js 回调函数真正的问题在于他剥夺了我们使用 return 和 throw 这些关键字的能力.而 Promise 很好地解决了这一切. 2015 年 6 月,ECMAScript 6 的正式版 终于发布了. ECMAScript 是 JavaScript 语言的国际标准,JavaScript 是 ECMAScript 的实现.ES6 的目标,是使得 JavaScript 语言可以用来编写大型的复杂的应用程序,成为企业级开发语言. 概念 ES6 原生提供了 Promise 对

  • 详细解读JavaScript编程中的Promise使用

    Promise核心说明 尽管Promise已经有自己的规范,但目前的各类Promise库,在Promise的实现细节上是有差异的,部分API甚至在意义上完全不同.但Promise的核心内容,是相通的,它就是then方法.在相关术语中,promise指的就是一个有then方法,且该方法能触发特定行为的对象或函数. Promise可以有不同的实现方式,因此Promise核心说明并不会讨论任何具体的实现代码. 先阅读Promise核心说明的意思是:看,这就是需要写出来的结果,请参照这个结果想一想怎么用

  • JavaScript中的Promise使用详解

    许多的语言,为了将异步模式处理得更像平常的顺序,都包含一种有趣的方案库,它们被称之为promises,deferreds,或者futures.JavaScript的promises ,可以促进关注点分离,以代替紧密耦合的接口. 本文讲的是基于Promises/A 标准的JavaScript promises.[http://wiki.commonjs.org/wiki/Promises/A] Promise的用例: 执行规则 多个远程验证 超时处理 远程数据请求 动画 将事件逻辑从应用逻辑中解耦

  • JavaScript异步编程Promise模式的6个特性

    在我们开始正式介绍之前,我们想看看Javascript Promise的样子: 复制代码 代码如下: var p = new Promise(function(resolve, reject) {  resolve("hello world");}); p.then(function(str) {  alert(str);}); 1. then()返回一个Forked Promise 以下两段代码有什么区别呢? 复制代码 代码如下: // Exhibit Avar p = new Pr

  • 举例详解JavaScript中Promise的使用

    摘录 – Parse JavaScript SDK现在提供了支持大多数异步方法的兼容jquery的Promises模式,那么这意味着什么呢,读完下文你就了解了. "Promises" 代表着在javascript程序里下一个伟大的范式,但是理解他们为什么如此伟大不是件简单的事.它的核心就是一个promise代表一个任务结果,这个任务有可能完成有可能没完成.Promise模式唯一需要的一个接口是调用then方法,它可以用来注册当promise完成或者失败时调用的回调函数,这在Common

  • JavaScript Promise 用法

    同步编程通常来说易于调试和维护,然而,异步编程通常能获得更好的性能和更大的灵活性.异步的最大特点是无需等待."Promises"渐渐成为JavaScript里最重要的一部分,大量的新API都开始promise原理实现.下面让我们看一下什么是promise,以及它的API和用法! Promises现状 XMLHttpRequest API是异步的,但它没有使用promise API.但有很多原生的 javascript API 使用了promise: *Battery API *fetc

  • AngularJS中处理多个promise的方式

    在使用AngularJS中处理promise的时候,有时会碰到需要处理多个promise的情况. 最简单的处理就是每个promise都then.如下: var app = angular.module("app",[]); app.controller("AppCtrl", function($q. $timeout){ var one = $q.defer(); var two = $q.defer(); var three = $q.defer(); $time

  • 理解JavaScript中Promise的使用

    Javascript 采用回调函数(callback)来处理异步编程.从同步编程到异步回调编程有一个适应的过程,但是如果出现多层回调嵌套,也就是我们常说的厄运的回调金字塔(Pyramid of Doom),绝对是一种糟糕的编程体验.于是便有了 CommonJS 的 Promises/A 规范,用于解决回调金字塔问题.本文先介绍 Promises 相关规范,然后再通过解读一个迷你的 Promises 以加深理解. 什么是 Promise 一个 Promise 对象代表一个目前还不可用,但是在未来的

随机推荐