首页 > 技术文章 > Promise的理解

ning123 2019-06-08 19:39 原文

1,什么是Promise

Promise对象用于异步操作,它表示一个尚未完成且预计在未来完成的异步操作。

1.1,同步和异步的概念

JavaScript的执行环境是单线程;

所谓单线程,是指JS引擎中负责解释和执行JavaScript代码的线程只有一个,也就是一次只能完成一项任务,这个任务执行完后才能执行下一个,它会「阻塞」其他任务。这个任务可称为主线程。

但实际上还有其他线程,如事件触发线程、ajax请求线程等。

1.1.1 同步

同步模式,一次只能执行一个任务,函数调用后需要等到函数执行结束,

返回执行结果,才能进行下一个任务。如果这个任务执行的时间较长。

就会导致线程阻塞。

var x = true;
while(x);
console.log("don't carry out"); //并不会执行这句

while是一个死循环,它会阻塞进程,因此后面的console并不会执行。

1.1.2 异步

异步与同步模式相反,可以一起执行多个任务。函数的调用不会立马返回执行结果。

如果A任务需要等待(如读取文件),可先执行B任务。等A任务结果返回再继续回调。

 

setTimeout(function(){
   console.log('task A, asynchronous');
},0);

console.log('Task B, synchronous');


-------output--------
task B, ....
task A, ....

我们可以看到,定时器延时的时间明明是0,但是task A 还是比task B后执行。

原因是定时器是异步的,异步任务会在同步任务执行完之后才会执行。

因为同步任务阻塞了进程。

 

1.1.3 回调函数

异步,必须提到回调函数。

setTimeout里面的function就是回调函数。

可以理解为:执行完 调用的 函数。

回调函数不仅可以用于异步调用,一般的同步场景也可以回调。

同步:回调函数一般是最后执行;

异步:一段时间后执行或者不执行(没有达到执行条件)。

/*    同步回调   */
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 3000ms    
    }
    console.log("I‘am callback");
}
fun1(fun2);

------output-----
before callback
//after 3000ms
I ' am callback
//再执行同步回调
after callback

 

1.2 为什么使用Promise

Promise是基于异步操作的。

既然我们可以使用异步回调的进行异步操作,为什么还要使用Promise呢?

function sendRequest(url , param){
    return new Promise(fiunctiuon (resolve,reject) {
         request (url , param, resolve, reject);
    });
}


sendRequest('test.html' , ' ' ).then (function(data) {
    //异步操作成功后回调
    console.log('请求成功,这是返回的数据:' , data);
} function (error){
    //异步操作失败的回调
     console.log('sorry,请求失败了,这是失败信息:’) ,error);
}
);

 

上述的Promise 的简单用法;

我们可以看到Promise 的强大的之处是:多重链式调用;

 

sendRequest('test1.html', '').then(function(data1) {
    console.log('第一次请求成功, 这是返回的数据:', data1);
    return sendRequest('test2.html', data1);
}).then(function(data2) {
    console.log('第二次请求成功, 这是返回的数据:', data2);
    return sendRequest('test3.html', data2);
}).then(function(data3) {
    console.log('第三次请求成功, 这是返回的数据:', data3);
}).catch(function(error) {
    //用catch捕捉前面的错误
    console.log('sorry, 请求失败了, 这是失败信息:', error);
});

 

2.Promise的基本用法

2.1 基本用法

promise对象代表一个未完成,但预计将来会完成的操作。

promise的三种状态:

  1. pending : 初始值,不是fulfilled,也不是rejected

  2. fulfilled :  代表操作成功

  3. 代表操作失败

Promise 有两种状态改变的方式,既可以从pending 转变成fulfilled,

也可以从pending 转变成rejected.一旦状态发生改变。就不再发生变化。

之后执行 promise.then绑定的函数。

* : Promise 一旦新建就会立即执行,无法取消。这也是它的缺点之一。

 

var promise =  new Promise ( function (resolve, reject ) {
    if (/* 异步操作成功 */){
          resolve(data);
    }else{
       /* 异步操作失败 */
       rejected (error);
    }
})

使用new 关键字构建 Promise。

Promise 接受一个函数作为参数,函数的两个参数分别是 resolve,rejected

这两个函数就是回调函数,由JavaScript引擎提供。

resolve 函数的作用: 再异步操作成功时调用,并将异步操作,作为参数传递出去;

rejected 函数的作用: 再异步操作失败时调用,并将异步操作,作为参数传递出去;

 

Promise实例生成以后,可以用then方法指定resolve状态和reject状态的回调函数。

 1 var promise = new Promise(function (resolve, reject) {
 2     if (/* 异步操作成功 */) {
 3         resolve(data);
 4     } else {
 5         /* 异步操作失败 */
 6         reject(error);
 7     }
 8 });
 9 
10 promise.then( onFulfilled, onRejected);
11  
12 promise.then(function(data) {
13     //do something when success
14 }.function (error) {
15     //do something when failure 
16 });

 

 

2.2 基本API

.then ()

语法:Promise.prototype.then( onFulfilled, onRejected)

对promise添加onFulfilled 和 onRejected回调

并返回一个新的Promise实例。

且返回值作为参数传入新的promise的resolve函数。

 

.catch ()

语法:Promise.prototype.catch( onRejected)

该方法是.then ( undefined, onRejected)的别名,用于指定发生错误时的回调函数。

 1 promise.then(function(data) {
 2     console.log('success');
 3 }).catch(function(error) {
 4     console.log('error', error);
 5 });
 6 
 7 /*******等同于*******/
 8 promise.then(function(data) {
 9     console.log('success');
10 }).then(undefined, function(error) {
11     console.log('error', error);
12 });

 

reject方法的作用,等同于抛错。

 

 

.all ()

语法:Promise.all( iterable)

该方法用于多个promise实例,包装成一个新的promise实例

1 var p = Promise.all( [p1,p2,p3] )

 

Promise.all方法接受一个数组(或具有Iterator接口)作参数,数组中的对象(p1、p2、p3)均为promise实例(如果不是一个promise,该项会被用Promise.resolve转换为一个promise)。它的状态由这三个promise实例决定。

  • 当p1, p2, p3状态都变为fulfilled,p的状态才会变为fulfilled,并将三个promise返回的结果,按参数的顺序(而不是 resolved的顺序)存入数组,传给p的回调函数,如例3.8。
  • 当p1, p2, p3其中之一状态变为rejected,p的状态也会变为rejected,并把第一个被reject的promise的返回值,传给p的回调函数,

 

.race ()

语法:Promise.race( iterable)

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

 

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

Promise.race方法同样接受一个数组(或具有Iterator接口)作参数。当p1, p2, p3中有一个实例的状态发生改变(变为fulfilledrejected),p的状态就跟着改变。并把第一个改变状态的promise的返回值,传给p的回调函数。

 

.resolve()

语法:

Promise.resolve(value);
Promise.resolve(promise);
Promise.resolve(thenable);

它可以看做new Promise()的快捷方式。

Promise.resolve('Success');

/*******等同于*******/
new Promise(function (resolve) {
    resolve('Success');
});

 

.reject()

语法:Promise.reject(reason)

这个方法和上述的Promise.resolve()类似,它也是new Promise()的快捷方式。

Promise.reject(new Error('error'));

/*******等同于*******/
new Promise(function (resolve, reject) {
    reject(new Error('error'));
});

 

关于promise就先介绍到这边了,比较基础,有不足的地方欢迎指出,有更好的也欢迎补充~

参考资料:

推荐阅读