浅谈promise和js执行机制(一)
栏目: JavaScript · 发布时间: 6年前
内容简介:今天有时间翻到了es6的promise,可能大家都对此熟悉不过,我之前一直觉得promise也很简单,但是今天确实让我对promise有了一个新的了解,以前的理解可能是错误的。。。先来看看官方的promise的定义是:初读上面这段话我读了不下5次,但是我还是没能真正了解其真正表达的意思,于是我查阅了部分资料,终于找到了一个比较容易理解的说法,这个估计小白应该是可以看得懂得。就拿做饭吃饭洗碗来举例子吧,这是三个步骤,第一步做饭,再第二步吃饭的时候我们需要拿到第一步做的饭,在第三步洗碗的时候我们需要拿到第二步的
作为一个入门级前端,今天是一个非常值得纪念的日子,因为这是我第一次在论坛上发表帖子,作为起步。虽然我觉得自己水平还是十分的有限,对一些细节的理解还不是很透彻,但是还是要迈出这一步,不管是给别的新手作为学习参考,还是自己以后回顾,总觉得需要把自己的成长记录下来,希望自己以后还是要多坚持,如果有不对的地方还是希望大家及时提出来,共同进步
今天有时间翻到了es6的promise,可能大家都对此熟悉不过,我之前一直觉得promise也很简单,但是今天确实让我对promise有了一个新的了解,以前的理解可能是错误的。。。先来看看官方的promise的定义是:
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
特点:
(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
初读上面这段话我读了不下5次,但是我还是没能真正了解其真正表达的意思,于是我查阅了部分资料,终于找到了一个比较容易理解的说法,这个估计小白应该是可以看得懂得。
就拿做饭吃饭洗碗来举例子吧,这是三个步骤,第一步做饭,再第二步吃饭的时候我们需要拿到第一步做的饭,在第三步洗碗的时候我们需要拿到第二步的碗筷,而且这三个步骤必须是按照顺序执行,有严格的先后顺序。
//做饭 function cook(){ console.log('开始做饭。'); var p = new Promise(function(resolve, reject){ //做一些异步操作 setTimeout(function(){ console.log('做饭完毕!'); resolve('鸡蛋炒饭'); }, 1000); }); return p; } //吃饭 function eat(data){ console.log('开始吃饭:' + data); var p = new Promise(function(resolve, reject){ //做一些异步操作 setTimeout(function(){ console.log('吃饭完毕!'); resolve('一个碗和一双筷子'); }, 2000); }); return p; } //洗碗 function wash(data){ console.log('开始洗碗:' + data); var p = new Promise(function(resolve, reject){ //做一些异步操作 setTimeout(function(){ console.log('洗碗完毕!'); resolve('干净的碗筷'); }, 2000); }); return p; } //函数调用 cook().then(res1 => { console.log(res1,'这是第一步传递给第二步的参数') return eat(res1) }).then(res2 => { console.log(res2,'这是第二步传给第三步的参数') return wash(res2) }).then(res3 => { console.log(res3,'饭吃完了还你干净的碗筷') }) 复制代码
结果如下:
看完上面的代码大家可能会有好多疑问,我在这里把我当时初学promise的疑问和大家分享一下:
(1)为什么我要在promise对象外面需要用一个函数来包裹起来呢?
答:Promise也有一些缺点。首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
这是promise的一些缺点, 一旦新建它就会立即执行 所以为了控制这个promise对象什么时候执行,在开发过程中我们需要在外面包裹一个函数,通过调用函数的形式来控制promise的执行。大家可以在自己的编辑器中试试。
new Promise(function(resolve, reject) { setTimeout(()=> { console.log('开车!!!') },2000) }); 复制代码
(2)在每一个函数中我为什么要将我的promise对象用一个变量接收然后return出去呢?
答:因为有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。
//函数调用 cook().then(res1 => { console.log(res1,'这是第一步传递给第二步的参数') return eat(res1) }).then(res2 => { console.log(res2,'这是第二步传给第三步的参数') return wash(res2) }).then(res3 => { console.log(res3,'饭吃完了还你干净的碗筷') }) 复制代码
大家看我的这段代码 在执行了cook()函数的时候cook函数return出来一个promise对象,promise对象上有.then()或.catch()方法,那么直接cook().then就可以在.then()方法中我们可以拿到promise对象中向外传递的参数,这个参数我们将传递给下一个eat()函数,作为eat()函数的参数继续执行。 而eat()函数也return了一个promise对象。那么我们将我们的这段代码拆解一下:
第一步: cook() //拿到的是cook return出来的promise对象 第二步: cook().then(res => { console.log(res) //拿到内部向外部传递的参数 }) 第三步: cook().then(res => { console.log(res) return eat(res) //eat执行以后return的是eat的promise对象,然后再把这个对象继续向外return }) //那么第三步的最终结果就是eat()的promise对象 第四步: cook().then(res => { console.log(res) return eat(res) //此时的结果是eat()的promise对象 }).then(res2 => { // 此时eat的promise又有.then方法 .....以此类推 }) 复制代码
我们就这样一步一步的完成了整个做饭、吃饭、洗碗的整个流程。 纵观以上代码你会发现虽然每一个操作流程中我都是以异步函数setTimeout来进行的,但是在调用过程中确是按照 做饭-吃饭-洗碗的正常流程表达的。这不是promise的 有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数
(3)如何判断失败的情况呢?
//做饭 function cook(){ console.log('开始做饭。'); var p = new Promise(function(resolve, reject){ //做一些异步操作 setTimeout(function(){ console.log('饭糊了....没法吃'); reject('糊了的饭'); }, 1000); }); return p; } //吃饭 function eat(data){ console.log('开始吃饭:' + data); var p = new Promise(function(resolve, reject){ //做一些异步操作 setTimeout(function(){ console.log('吃饭完毕!'); resolve('一个碗和一双筷子'); }, 2000); }); return p; } cook().then(res1 => { console.log(res1,'这是第一步传递给第二步的参数') return eat(res1) }).catch(err => { console.log(err,'返回错误') }) 复制代码
catch()方法用来指定 reject 的回调。
(4)如何在多个异步操作都完成后才执行回调呢?
function tackBus1(){ var p = new Promise(function(resolve, reject){ //做一些异步操作 setTimeout(function(){ console.log('甲正在上车'); resolve('甲坐好了'); }, 1000); }); return p; } function tackBus2(){ var p = new Promise(function(resolve, reject){ //做一些异步操作 setTimeout(function(){ console.log('乙正在上车'); resolve('乙坐好了'); }, 2000); }); return p; } function tackBus3(){ var p = new Promise(function(resolve, reject){ //做一些异步操作 setTimeout(function(){ console.log('丙正在上车'); resolve('丙坐好了'); }, 3000); }); return p; } Promise.all([tackBus1(),tackBus2(),tackBus3()]).then(res => { console.log(res) }) 复制代码
司机在等人上车,在乘客都坐稳了以后开车发车,这就用Promise.all来执行,all接收一个数组参数,里面的值最终都算返回Promise对象。这样,三个异步操作的并行执行的,等到它们都执行完后才会进到then里面。那么,三个异步操作返回的数据哪里去了呢?都在then里面呢,all会把所有异步操作的结果放进一个数组中传给then,就是上面的results。所以上面代码的输出结果就是:
这是.all的方法,promise还有一种.race的方法,它和all方法的区别就是: all方法的效果实际上是谁跑的慢,以谁为准执行回调,那么相对的就有另一个方法谁跑的快,以谁为准执行回调,刚刚的执行结果我设置了他们的时间间隔分别是1s,2s,3s,在等最慢的执行完以后才执行了all这个回调方法,现在咱们来试试promise.race方法
function tackBus1(){ var p = new Promise(function(resolve, reject){ //做一些异步操作 setTimeout(function(){ console.log('甲正在上车'); resolve('甲坐好了'); }, 1000); }); return p; } function tackBus2(){ var p = new Promise(function(resolve, reject){ //做一些异步操作 setTimeout(function(){ console.log('乙正在上车'); resolve('乙坐好了'); }, 2000); }); return p; } function tackBus3(){ var p = new Promise(function(resolve, reject){ //做一些异步操作 setTimeout(function(){ console.log('丙正在上车'); resolve('丙坐好了'); }, 3000); }); return p; } Promise.race([tackBus1(),tackBus2(),tackBus3()]).then(res => { console.log(res) }) 复制代码
结果如下:
可以看出来在甲执行完毕后立即就执行了.race()方法,但是不耽误其他两个异步操作的进行,.race()中拿到的参数也只是当前最先执行完的异步操作中传递出来的参数。
(4)由promise联系到的js的宏任务和微任务
在看到promise的时候有一个地方还是令我有困惑,现在先留一个悬念,大家可以先看看下面这段代码,你觉得输出结果是什么呢? 我们下回见!
setTimeout(function(){ console.log('1') }); new Promise(function(resolve){ console.log('2'); resolve(); }).then(function(){ console.log('3') }); console.log('4'); 复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 彻底吃透 JavaScript 执行机制
- 深入理解js的执行机制
- JavaScript 同步和异步(执行机制)
- Microsoft Teams 升级机制允许黑客执行任意文件
- react源码浅析(六):多次执行setState的更新机制
- 【安全帮】Microsoft Teams 升级机制允许黑客执行任意文件
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Python Algorithms
Magnus Lie Hetland / Apress / 2010-11-24 / USD 49.99
Python Algorithms explains the Python approach to algorithm analysis and design. Written by Magnus Lie Hetland, author of Beginning Python, this book is sharply focused on classical algorithms, but it......一起来看看 《Python Algorithms》 这本书的介绍吧!