Promise 笔记

1. Promise 创建

Promise 对象是用于处理延时和异步调用场景,ES6中已经定稿,这个是未来的趋势

初始化对象

	new Promise(function(resolve, reject) {
		resolve('success');
	}).then(function(arg){
		console.log(arg);//success
	}).then(function(arg){
		console.log(arg);//success
	});

对于Promise对象的链式处理方式

	p.then(onFulfilled, onRejected);
	p.then(function(value) {
	
  	}, function(reason) {
  	
	});
2. 异常处理

catch 和 Promise.prototype.then(undefined, onRejected) 是等同的,当需要注意的是其中catch和then的onRejected方法只能捕获一次异常

	var p1 = new Promise(function(resolve, reject) {
        resolve('Success');
    });

    p1.then(function(value) {
        console.log(value); // "Success!"
        throw 'oh, no!'; // 抛出一个异常
    }).catch(function(e) {
        console.log(e); // "oh, no!" 异常被捕获
    }).then(function() {
        console.log('after a catch the chain is restored');
    }, function() {
        console.log('Not fired due to the catch'); // 再次绑定捕获也不会再次被触发
    });

    // The following behaves the same as above
    p1.then(function(value) {
        console.log(value); // "Success!"
        return Promise.reject('oh, no!'); // 再次发起一个异常
    }).catch(function(e) {
        console.log(e); // "oh, no!"
    }).then(function() {
        console.log('after a catch the chain is restored');
    }, function() {
        console.log('Not fired due to the catch'); //同样也不会被捕获
    });

如果强制抛出了两次异常,例如:

var pro = new Promise(function(resolve, reject){
    setTimeout(function(){
        reject(new Error('this is error'));
    },1000);
}).then(function(arg){
    return Promise.reject('this is error 2');
}).catch(function(arg){
    console.log(arg); // Error('this is error')
}).catch(function(arg){
    console.log(arg); //undefined
});

这种场景下只有第一个异常会被捕获

3. Promise.all 监听多个promise的状态
// `delay`毫秒后执行resolve
function timerPromisefy(delay) {
    return new Promise(function (resolve) {
        setTimeout(function () {
            resolve(delay);
        }, delay);
    });
}
var startDate = Date.now();
// 所有promise变为resolve后程序退出
Promise.all([
    timerPromisefy(1),
    timerPromisefy(32),
    timerPromisefy(64),
    timerPromisefy(128)
]).then(function (values) {
    console.log(Date.now() - startDate + 'ms');  // 約128ms
    console.log(values);    // [1,32,64,128]
});

必须等到所有的promise 的状态都变成FulFilled 之后才会触发all的成功方法

4. Promise.race 监听多个promise
// `delay`毫秒后执行resolve
function timerPromisefy(delay) {
    return new Promise(function (resolve) {
        setTimeout(function () {
            resolve(delay);
        }, delay);
    });
}
// 任何一个promise变为resolve或reject 的话程序就停止运行
Promise.race([
    timerPromisefy(1),
    timerPromisefy(32),
    timerPromisefy(64),
    timerPromisefy(128)
]).then(function (value) {
    console.log(value);    // => 1
});

只要有任意的一个promise对象变成FulFilled状态,then中的方法就会被调用

再看看如果第一个promise执行完之后,其他的promise会不会继续执行

var winnerPromise = new Promise(function (resolve) {
        setTimeout(function () {
            console.log('this is winner');
            resolve('this is winner');
        }, 4);
    });
var loserPromise = new Promise(function (resolve) {
        setTimeout(function () {
            console.log('this is loser');
            resolve('this is loser');
        }, 1000);
    });
// 第一个promise变为resolve后程序停止
Promise.race([winnerPromise, loserPromise]).then(function (value) {
    console.log(value);    // => 'this is winner'
});

从结果来看其他的promise还是会继续执行的

5. 使用reject而不是throw

参考: http://liubin.org/promises-book/#not-throw-use-reject

Promise的构造函数,以及被 then 调用执行的函数基本上都可以认为是在 try...catch 代码块中执行的,所以在这些代码中即使使用 throw ,程序本身也不会因为异常而终止。

如果在Promise中使用 throw 语句的话,会被 try...catch 住,最终promise对象也变为Rejected状态。

var promise = new Promise(function(resolve, reject){
    throw new Error("message");
}).catch(function(error){
    console.error(error);// => "message"
});

使用reject的优点

  • 如果使用throw的话很难区分是我们主动抛出来的还是真正的其他异常,在Chrome中有 Pause On Caught Exceptions 不能区分
  • 在 then 中使用reject的方法
var onRejected = console.error.bind(console);
var promise = Promise.resolve();
promise.then(function () {
    return Promise.reject(new Error("this promise is rejected"));
}).catch(onRejected);

这样在 then 方法中可以很方便的控制流程,同时传递任意的参数

6. 最佳实践

实现一个超时调用

function delayPromise(ms) {
    return new Promise(function (resolve) {
        setTimeout(resolve, ms);
    });
}

delayPromise(100).then(function () {
    console.log("已经过了100ms!");
});

这样的超时调用更加的优雅

posted @ 2016-03-22 23:18  咖啡+  阅读(167)  评论(0编辑  收藏  举报