首先,推荐一波Promise入门视频课程:Promise入门基础视频教程-慕课网(讲解得还不错,只是不知为何评分那么低!)
一、前言
本文主要对ES6的Promise进行一些入门级的介绍。要想学习一个知识点,肯定是从三个方面出发,what、why、how。下面就跟着我一步步学习吧~
二、什么是 Promise
首先是what。那么什么是Promise呢?
以下是MDN对Promise的定义:
The Promise object is used for asynchronous computations. A Promise represents a single asynchronous operation that hasn't completed yet, but is expected in the future.
译文:Promise对象用于异步操作,它表示一个尚未完成且预计在未来完成的异步操作。
那么什么是异步操作?在学习promise之前需要把这个概念搞明白,下面将抽离一章专门介绍。
2.1、同步与异步
我们知道,JavaScript的执行环境是「单线程」。
所谓单线程,是指JS引擎中负责解释和执行JavaScript代码的线程只有一个,也就是一次只能完成一项任务,这个任务执行完后才能执行下一个,它会「阻塞」其他任务。这个任务可称为主线程。
但实际上还有其他线程,如事件触发线程、ajax请求线程等。
这也就引发了同步和异步的问题。
2.1.1、同步
同步模式,即上述所说的单线程模式,一次只能执行一个任务,函数调用后需等到函数执行结束,返回执行的结果,才能进行下一个任务。如果这个任务执行的时间较长,就会导致「线程阻塞」。
/* 例2.1 */ var x = true; while(x); console.log("don't carry out"); //不会执行
上面的例子即同步模式,其中的while是一个死循环,它会阻塞进程,因此第三句console不会执行。
同步模式比较简单,也较容易编写。但问题也显而易见,如果请求的时间较长,而阻塞了后面代码的执行,体验是很不好的。因此对于一些耗时的操作,异步模式则是更好的选择。
2.1.2、异步
下面就来看看异步模式。
异步模式,即与同步模式相反,可以一起执行多个任务,函数调用后不会立即返回执行的结果,如果任务A需要等待,可先执行任务B,等到任务A结果返回后再继续回调。
最常见的异步模式就数定时器了,我们来看看以下的例子。
/* 例2.2 */ setTimeout(function() { console.log('taskA, asynchronous'); }, 0); console.log('taskB, synchronize'); //while(true); -------ouput------- taskB, synchronize taskA, asynchronous
我们可以看到,定时器延时的时间明明为0,但taskA还是晚于taskB执行。这是为什么呢?由于定时器是异步的,异步任务会在当前脚本的所有同步任务执行完才会执行。如果同步代码中含有死循环,即将上例的注释去掉,那么这个异步任务就不会执行,因为同步任务阻塞了进程。
2.1.3、回调函数
提起异步,就不得不谈谈回调函数了。上例中,setTimeout里的function便是回调函数。可以简单理解为:(执行完)回(来)调(用)的函数。
以下是WikiPedia对于callback的定义。
In computer programming, a callback is a piece of executable code that is passed as an argument to other code, which is expected to call back (execute) the argument at some convenient time.
可以看出,回调函数是一段可执行的代码段,它以「参数」的形式传递给其他代码,在其合适的时间执行这段(回调函数)的代码。
WikiPedia同时提到:
The invocation may be immediate as in a synchronous callback, or it might happen at a later time as in an asynchronous callback.
也就是说,回调函数不仅可以用于异步调用,一般同步的场景也可以用回调。在同步调用下,回调函数一般是最后执行的。而异步调用下,可能一段时间后执行或不执行(未达到执行的条件)。
/* 例2.3 */ /******************同步回调******************/ var fun1 = function(callback) { //do something console.log("before callback"); (callback && typeof(callback) === 'function') && callback(); console.log("after callback"); } var fun2 = function(param) { //do something var start = new Date(); while((new Date() - start) < 3000) { //delay 3s } console.log("I'm callback"); } fun1(fun2); -------output-------- before callback //after 3s I’m callback after callback