Promise 笔记

1 理论概念

1.1 背景

在前端开发过程中,使用异步编程方式,避免不了使用回调函数(callback), 多嵌套的callback函数将导致代码阅读性差,不利于后期维护。 甚至有个形象名称“回调地狱”。为了解决该问题,提出了 Promise 解决方案。

1.2 回调地狱

当业务逻辑复杂的时候,回调的嵌套过多,代码复杂度增加,可读性降低,维护起来也复杂,调试也复杂,这就是回调地狱。

asyncFunc1(opt, (...args1) => {
    asyncFunc2(opt, (...args2) => {
        asyncFunc3(opt, (...args3) => {
            asyncFunc4(opt, (...args4) => {
                // some operation
            });
        });
    });
});

2 实战

2.1 创建 Promise

可以使用 new Promise(function(resolve, reject) {})创建一个 Promise 对象,在业务逻辑中成功时调用 resolve 方法, 失败时调用 reject 方法。

    /**
     * 异步调用服务
     */
    function invokeServiceAsync(beanId, method, params, callback) {

        var request = {};
        request.beanId = beanId;
        request.method = method
        request.params = params;

        var str = $.toJSON(request);

        window.cefQuery({
            request : str,
            onSuccess : function(response) {
                var result = $.parseJSON(response);
                callback && callback.call(null, result);
            }
        });

    }

    /**
     * 
     */
    function promiseServiceAsync(beanId, method, params) {
        var p = new Promise(function(resolve, reject) {
            invokeServiceAsync(beanId, method, params, resolve);
        });
        return p;
    }

2.2 使用 then

调用方可使用 then 方法处理成功,编程模式按顺序,可阅读。

var str = $.toJSON(deEntity)
var promise = utils.promiseServiceAsync("zmDataBuildService", "generateZmSpendsByDeStr", [ str ]);
promise.then(function(result) {
    data.zmSpends = result.data;
    data.deEntity = null;
    self.updateRow(data);
});

2.3 串行执行

有若干个异步任务,需要先做任务1,如果成功后再做任务2,任何任务失败则不再继续并执行错误处理函数。要串行执行这样的异步任务,不用Promise需要写一层一层的嵌套代码。有了Promise,我们只需要简单地写:

job1.then(job2).then(job3).catch(handleError);
// 0.5秒后返回input*input的计算结果:
function multiply(input) {
     
    return new Promise(function (resolve, reject) {
     
        log('calculating ' + input + ' x ' + input + '...');
        setTimeout(resolve, 500, input * input);
    });
}

// 0.5秒后返回input+input的计算结果:
function add(input) {
     
    return new Promise(function (resolve, reject) {
     
        log('calculating ' + input + ' + ' + input + '...');
        setTimeout(resolve, 500, input + input);
    });
}

var p = new Promise(function (resolve, reject) {
     
    log('start new Promise...');
    resolve(123);
});

p.then(multiply)
 .then(add)
 .then(multiply)
 .then(add)
 .then(function (result) {
     
    log('Got value: ' + result);
});

2.4 并行执行

除了串行执行若干异步任务外,Promise还可以并行执行异步任务。

var p1 = new Promise(function (resolve, reject) {
     
    setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
     
    setTimeout(resolve, 600, 'P2');
});
// 同时执行p1和p2,并在它们都完成后执行then:
Promise.all([p1, p2]).then(function (results) {
     
    console.log(results); // 获得一个Array: ['P1', 'P2']
});

2.5 比赛执行

有些时候,多个异步任务是为了容错。比如,同时向两个URL读取用户的个人信息,只需要获得先返回的结果即可。这种情况下,用Promise.race()实现:

var p1 = new Promise(function (resolve, reject) {
     
    setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
     
    setTimeout(resolve, 600, 'P2');
});
Promise.race([p1, p2]).then(function (result) {
     
    console.log(result); // 'P1'
});

由于p1执行较快,Promise的then()将获得结果’P1’。p2仍在继续执行,但执行结果将被丢弃。

你可能感兴趣的:(前端,promise)