目录

1.Promise介绍

2.Promise语法

2.1构造方法

2.2Promise示例

2.3Promise对象串联

2.4Promise执行并行任务

3.Promise网络请求示例


在JavaScript的世界中,所有代码都是单线程执行的。

由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行。

1.Promise介绍

Promise对象表示异步操作的最终完成(或失败)及其结果值。

Promise是创建promise时不一定知道的值的代理。它允许您将处理程序与异步操作的最终成功值或失败原因相关联。这允许异步方法返回类似于同步方法的值:异步方法返回一个承诺(Promise),以便在将来的某个时刻提供值。

Promise有如下状态:

a.pending:初始化状态,既不是操作完成也不是操作失败;

b.fulfilled:意思是操作已经成功操作;

c.rejected:意思是操作失败;

2.Promise语法

2.1构造方法

new Promise( function(resolve, reject) {...} /* executor */  );

executor(参数)

executor是带有 resolve 和 reject 两个参数的函数 。Promise构造函数执行时立即调用executor 函数, resolve 和 reject 两个函数作为参数传递给executor(executor 函数在Promise构造函数返回所建promise实例对象前被调用)。resolve 和 reject 函数被调用时,分别将promise的状态改为fulfilled(完成)或rejected(失败)。executor 内部通常会执行一些异步操作,一旦异步操作执行完毕(可能成功/失败),要么调用resolve函数来将promise状态改成fulfilled,要么调用reject 函数将promise的状态改为rejected。如果在executor函数中抛出一个错误,那么该promise 状态为rejected。executor函数的返回值被忽略。

2.2Promise示例

我们先看一个最简单的Promise例子:生成一个0-2之间的随机数,如果小于1,则等待一段时间后返回成功,否则返回失败:

function test(resolve, reject) {
    var timeOut = Math.random() * 2;
    log('set timeout to: ' + timeOut + ' seconds.');
    setTimeout(function () {
        if (timeOut < 1) {
            log('call resolve()...');
            resolve('200 OK');
        }
        else {
            log('call reject()...');
            reject('timeout in ' + timeOut + ' seconds.');
        }
    }, timeOut * 1000);
}

这个test()函数有两个参数,这两个参数都是函数,如果执行成功,我们将调用resolve('200 OK'),如果执行失败,我们将调用reject('timeout in ' + timeOut + ' seconds.')。可以看出,test()函数只关心自身的逻辑,并不关心具体的resolvereject将如何处理结果。

有了执行函数,我们就可以用一个Promise对象来执行它,并在将来某个时刻获得成功或失败的结果:

var p1 = new Promise(test);
var p2 = p1.then(function (result) {
    console.log('成功:' + result);
});
var p3 = p2.catch(function (reason) {
    console.log('失败:' + reason);
});

变量p1是一个Promise对象,它负责执行test函数。由于test函数在内部是异步执行的,当test函数执行成功时,我们告诉Promise对象:

// 如果成功,执行这个函数:
p1.then(function (result) {
    console.log('成功:' + result);
});

test函数执行失败时,我们告诉Promise对象:

p2.catch(function (reason) {
    console.log('失败:' + reason);
});

2.3Promise对象串联

Promise对象可以串联起来,所以上述代码可以简化为:

new Promise(test).then(function (result) {
    console.log('成功:' + result);
}).catch(function (reason) {
    console.log('失败:' + reason);
});

实际测试一下,看看Promise是如何异步执行的:

new Promise(function (resolve, reject) {
    log('start new Promise...');
    var timeOut = Math.random() * 2;
    log('set timeout to: ' + timeOut + ' seconds.');
    setTimeout(function () {
        if (timeOut < 1) {
            log('call resolve()...');
            resolve('200 OK');
        }
        else {
            log('call reject()...');
            reject('timeout in ' + timeOut + ' seconds.');
        }
    }, timeOut * 1000);
}).then(function (r) {
    log('Done: ' + r);
}).catch(function (reason) {
    log('Failed: ' + reason);
});

输出日志:
 

start new Promise...

set timeout to: 0.9423536828591128 seconds.

call resolve()...

Done: 200 OK

可见Promise最大的好处是在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了:

Promise还可以做更多的事情,比如,有若干个异步任务,需要先做任务1,如果成功后再做任务2,任何任务失败则不再继续并执行错误处理函数。

要串行执行这样的异步任务,不用Promise需要写一层一层的嵌套代码。有了Promise,我们只需要简单地写:

job1.then(job2).then(job3).catch(handleError);

其中,job1job2job3都是Promise对象。

下面的例子演示了如何串行执行一系列需要异步计算获得结果的任务:

// 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);
});

setTimeout可以看成一个模拟网络等异步执行的函数。

异步操作输出结果:

start new Promise...

calculating 123 x 123...

calculating 15129 + 15129...

calculating 30258 x 30258...

calculating 915546564 + 915546564...

Got value: 1831093128

2.4Promise执行并行任务

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

试想一个页面聊天系统,我们需要从两个不同的URL分别获得用户的个人信息和好友列表,这两个任务是可以并行执行的,用Promise.all()实现如下:

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']
});

有些时候,多个异步任务是为了容错。比如,同时向两个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,就可以把很多异步任务以并行和串行的方式组合起来执行。

3.Promise网络请求示例

Promise对象串联,采用责任链的方式执行异步操作,Promise.then().then().catch();,可以简化代码

 /** * POST 请求,经测试用FormData传递数据也可以 */
    static post(url, params, success, fail, error){
        // new Request();
        console.log(url,params)
        fetch(url,{ method: 'POST',
            headers:{
                'Accept': '*/*',
                //媒体格式类型key/value格式
                // 'Accept': 'application/json;charset=UTF-8',
                'Content-Type': 'multipart/form-data'
            },
            body: params//JSON.stringify(params)
        }).then(response=>response.json())
            //把response转为json
        .then(responseJson=> {
            // 拿到上面的转好的json
            console.log(responseJson);
            // 打印返回结果
            if (responseJson.status == 0){
                // 0为请求成功
                success && success(responseJson.entity)
            }else {
                fail && fail(responseJson.entity)
                //可以处理返回的错误信息
            }
        }) .catch(e=>{
            console.log(e)
            error && error(error)
            // Alert.alert("e", e);
            Alert.alert("提示信息", "请检查您的网络是否已经连接");
        })
    }

参考:

https://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/0014345008539155e93fc16046d4bb7854943814c4f9dc2000

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐