ES6:Promise

ES6新增Promise用来实现异步函数,如下

new Promise((resolve, reject) => {
    setTimeout(function(){
        resolve(1000);
    }, 1000);
}).then(data => {
    console.log(data)
}).catch(err => {
    console.dir(err)
});
//1秒之后在控制台打印出1000

通过new关键字创建一个Promise实例,接受一个参数方法,在实例创建时该方法被执行,执行完成之后通过调用resolve()或reject()分别来触发then和catch,通过resolve方法传入参数做为then回调方法的参数,可以实现数据传递。

promise支持通过then方法的参数方法中返回新Promise实例来进行链式调用,并依次执行。

function p(ms){
    var f = new Promise((resolve, reject) => {
        setTimeout(function(){
            console.log(ms)
            resolve(ms+1)
        }, ms)
    })
    return f
}
p(1000).then(p).then(p).then(p)
//1秒之后在控制台打印出1000
//1秒之后在控制台打印出1001
//1秒之后在控制台打印出1002
//...

使用Axios发送多个相互依赖的异步请求时可以这样写

//异步请求队列封装
//传入参数对象paras,包含请求地址url,请求参数para,处理返回数据函数func
var axiosQueue = function(config){ 
    //返回新promise实例给下一个then方法
    return new Promise(function(resolve, reject){ 
	    axios.get(config.url, config.para)
	    .then(function (res) {
            //在这里可以对请求响应数据做一些操作
	        config.callback(res)
            //将操作过的返回数据传给then方法的参数方法作为参数
	        resolve(res);
	    }).catch(function (err) {
	      	reject(err)
	    })    
	})
}

//链式调用依次执行多个axios方法
axiosQueue({
    url:'url1',para:{a:1},callback:function(){}
}).then(axiosQueue({
    url:'url2',para:{a:2},callback:function(){}
})).then(axiosQueue({
    url:'url3',para:{a:3},callback:function(){
        console.log(res.data.data[2]);
    }
}))

//链式调用依次执行多个axios方法,并实现参数先后依赖
axiosQueue({ 
    url:'url1',para:{a:1},func:function(){}
}).then(data => {
    //将返回的数据作为新请求的参数
	var paras = {url:'url2',para:data.data,callback:function(res){}}
    //调用axiosQueue,将返回值(即新Promise实例)返回给then,实现链式调用
	return axiosQueue(paras) 
}).then(data => {
	var paras = {url:'url3',para:data.data.data[1],func:function(res){
        console.log(res.data.data[2]);
    }}
	return axiosQueue(paras)
})

//以上代码逻辑还可以这样实现
//通过Promise.resolve方法立即返回一个resolved状态的Promise对象,直接使用then进行链式调用
Promise.resolve().then(() => { 
	var paras = {url:'url1',para:{a:1},func:function(){}}
	return axiosQueue(paras) 
}).then(data => {
	var paras = {url:'url2',para:data.data.data[0],func:function(){}}
	return axiosQueue(paras)
}).then(data => {
	var paras = {url:'url3',para:data.data.data[1],func:function(res){
		console.log(res.data.data[2]);
	}}
	return axiosQueue(paras)
})

下面这段转载来的代码可以帮助理解Promise原理

function Promise(fn) {
    var state = 'pending',
        value = null,
        queue = [];

    this.then = function (onResolved, onRejected) {
        return new Promise(function (resolve, reject) {
            handle({
                onResolved: onResolved || null,
                onRejected: onRejected || null,
                resolve: resolve,
                reject: reject
            });
        });
    };

    function handle(callback) {
        if (state === 'pending') {
            queue.push(callback);
            return;
        }

        var cb = state === 'resolved' ? callback.onResolved : callback.onRejected,
            ret;
        if (cb === null) {
            cb = state === 'resolved' ? callback.resolve : callback.reject;
            cb(value);
            return;
        }

        try {
            ret = cb(value);
            callback.resolve(ret);
        } catch (e) {
            callback.reject(e);
        }
    }


    function resolve(newValue) {
        if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
            var then = newValue.then;
            if (typeof then === 'function') {
                then.call(newValue, resolve, reject);
                return;
            }
        }
        state = 'resolved';
        value = newValue;
        execute();
    }

    function reject(reason) {
        state = 'rejected';
        value = reason;
        execute();
    }

    function execute() {
        setTimeout(function () {
            queue.forEach(function (callback) {
                handle(callback);
            });
        }, 0);
    }

    fn(resolve, reject);
}
  1. 调用Promise方法(创建Promise实例),传入fn参数方法,fn接受两个参数,分别是resolve方法和reject方法
  2. Promise方法设置当前state状态为pending,value为null,调用then方法
  3. then方法将返回一个新的Promise实例用来实现链式调用,then方法可以接受onResolved和onRejected两个函数分别用来处理resoled和rejected两种状态,在创建新Promise实例的fn传入新的resolve和reject方法,并调用handle方法
  4. handle方法会将then传入的onResolved,onRejected和新的Promise实例传入的新的resolve、reject四个函数加入queue中
  5. Promise方法调用fn方法,执行fn方法内的自定义代码,如ajax等
  6. fn方法执行成功后应使用newValue作为参数来调用resolve方法(此时当前Promise事实上为resolved状态)
    1. 如果newValue是一个函数对象,即为resolve传入一个新Promise实例,则将resolve和reject作为参数传给这个新Promise实例的then方法并调用,至此当前Promise相当于执行结束,所以不需要更新state和value,直接进入新Promise实例的pending状态 接3
    2. 如果newValue是一个数据(对象),则将state更新为resolved,value更新为newValue,调用execute方法
  7. 接6.2 execute方法会遍历queue数组,使用queue中每个callback作为参数分别调用handle方法
  8. handle方法内通过判断当前state状态为resolved进而执行onResolved方法,
    1. 如果then中传入了onResolved方法,将value(此时为newValue)传给onResolved作为参数,然后将onResolved的返回值传给resolve方法并调用,至此当前Promise相当于执行结束
    2. 如果then中没有传入onResolved方法则执行resolve方法,将value(此时为newValue)传给resolve作为参数,至此当前Promise相当于执行结束

总结:

  1. 通过Promise.prototype.then和Promise.prototype.catch方法将观察者方法注册到被观察者Promise对象中,同时返回一个新的Promise对象,以便可以链式调用。
  2. 被观察者管理内部pending、fulfilled和rejected的状态转变,同时通过构造函数中传递的resolve和reject方法以主动触发状态转变和通知观察者

刚开始看promise源码的时候总不能很好的理解then和resolve函数的运行机理,但是如果你静下心来,反过来根据执行promise时的逻辑来推演,就不难理解了。这里一定要注意的点是:promise里面的then函数仅仅是注册了后续需要执行的代码,真正的执行是在resolve方法里面执行的,理清了这层,再来分析源码会省力的多。

Promise.all

Promise.all(arr) 方法接受一个有多个Promise实例组成的数组对象,返回一个新的Promise实例,该实例在arr参数内所有子Promise实例都成为resolved状态时执行父Promise实例的resolve方法,接受的所有子Promise实例结果数组作为参数;当arr参数内任一子Promise实例成为rejected状态,则执行其reject方法,不管其他子Promise实例是否执行完成,失败原因的是第一个rejected的Promise实例的reject方法的err参数。

通过Promise.all()方法可以实现多个异步函数并发,并在所有异步函数全部执行完成后执行回调函数。由于该方法返回值是一个Promise实例,所以可以使用then方法并进行链式调用。then的参数方法的参数为一个由数组中所有Promise实例的resolve方法的参数组成的数组。

var p1 = new Promise((resolve, reject) => { 
  setTimeout(resolve, 1000, 'one'); 
}); 
var p2 = new Promise((resolve, reject) => { 
  setTimeout(resolve, 2000, 'two'); 
});
var p3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 3000, 'three');
});
var p4 = new Promise((resolve, reject) => {
  setTimeout(resolve, 4000, 'four');
});
var p5 = new Promise((resolve, reject) => {
  reject('rejected');
});
//全部成功
Promise.all([p1, p2, p3, p4]).then(values => { 
  console.log(values);
  //在4秒后打印 ['one','two','three','four']
}, reason => {
  console.log(reason)
});

//有一个失败即失败
Promise.all([p1, p2, p3, p4, p5]).then(values => { 
  console.log(values);
}, reason => {
  console.log(reason)
  //立即打印出 'rejected'
});
//使用catch实现上面的代码
Promise.all([p1, p2, p3, p4, p5]).then(values => { 
  console.log(values);
}).catch(reason => { 
  console.log(reason)
//立即打印出 'rejected'
});

Promise.race

Promise.race(arr) 方法接受一个有多个Promise实例组成的数组对象,返回一个新的Promise实例,该实例在arr参数内任何一个子Promise实例成为resolved或rejected状态时执行父Promise实例的resolve或reject方法,其他子Promise实例会继续执行,但不会再触发父Promise实例的回调函数。

通过Promise.race()方法可以实现多个异步函数并发,并在任一异步函数执行完成后立即执行回调函数。由于该方法返回值是一个Promise实例,所以可以使用then方法并进行链式调用。then(或catch)的参数方法的参数为子Promise实例的resolve(或reject)方法的参数。

var p1 = new Promise((resolve, reject) => { 
  setTimeout(resolve, 1000, 'one'); 
}); 
var p2 = new Promise((resolve, reject) => { 
  setTimeout(resolve, 2000, 'two'); 
});
var p3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 3000, 'three');
});
var p4 = new Promise((resolve, reject) => {
  setTimeout(resolve, 4000, 'four');
});
var p5 = new Promise((resolve, reject) => {
  reject('rejected');
});
//任一成功
Promise.race([p1, p2, p3, p4]).then(values => { 
  console.log(values);
  //在1秒后打印 'one'
}, reason => {
  console.log(reason)
});

//任一失败
Promise.race([p1, p2, p3, p4, p5]).then(values => { 
  console.log(values);
}, reason => {
  console.log(reason)
  //立即打印出 'rejected'
});

Promise.allSettled

Promise.allSettled(arr) 方法接受一个有多个Promise实例组成的数组对象,在arr参数内所有子Promise实例全部完成(resolve或reject)后,返回全部子Promise的结果数组。Promise.allSettled不具有race和all方法的短路特性,而是会将每一个子Promise执行完。

通过Promise.allSettled()方法可以实现多个异步函数并发,并在所有异步函数执行完成后执行回调函数。由于该方法返回值是一个Promise实例,所以可以使用then方法并进行链式调用。then(或catch)的参数方法的参数为子Promise实例的resolve(或reject)方法的参数。

var p1 = new Promise((resolve, reject) => { 
  setTimeout(resolve, 1000, 'one'); 
}); 
var p2 = new Promise((resolve, reject) => { 
  setTimeout(resolve, 2000, 'two'); 
});
var p3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 3000, 'three');
});
var p4 = new Promise((resolve, reject) => {
  setTimeout(reject, 4000, 'four');
});
var p5 = new Promise((resolve, reject) => {
  setTimeout(reject, 5000, 'five');
});
//全部完成
Promise.allSettled([p1, p2, p3, p4, p5 ]).then(values => { 
  console.log(values);
    
});
/* 在5秒后打印 
[
   {status: "fulfilled", value: "one"},
   {status: "fulfilled", value: "two"},
   {status: "fulfilled", value: "three"},
   {status: "rejected", reason: "four"},
   {status: "rejected", reason: "five"} 
] 
*/

----------------------------------------------------------------------
原文:https://blog.csdn.net/qq_22844483/article/details/73655738 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值