yizihan / blog

Record
1 stars 0 forks source link

ES6 - Promise #17

Open yizihan opened 6 years ago

yizihan commented 6 years ago

Promise里面保存着未来才会结束的事件(通常是一个异步操作)的结果。 Promise是一个对象,从它可以获取异步操作的消息。 Promise是一个构造函数,用来生成Promise实例。 Promise新建之后就会立即执行

const promise = new Promise((resolve, reject) => {
    if(/*异步操作成功*/) {
        // 将Promise对象的状态从“未完成”变为“成功”,在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
        resolve(value);
    } else {
        // 将Promise对象的状态从“未完成”变为“失败”,在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去;
        reject(error);
    }
});
// Promise生成实例以后,可以用then方法分别指定resolved状态和rejected状态的回调函数
promise.then(function() {
    // success
}, function() {
    // failure
});

用Promise实现Ajax

const getJSON = function(url) {
    // 返回Promise
    return new Promise((resolve, reject) => {
        // 新建XML请求实例
        const client = new XMLHttpRequest;
        // 设置请求头
        client.setRequestHeader('Accept', 'application/json');
        // 设置接收数据格式
        client.responseType = 'json';
        // 开启请求
        client.open('GET', url);
        // 监听请求返回的内容
        client.onreadystatechange = function() {
            if(this.readyState !== 4) return;
            if(this.status === 200) {
                // 将成功得到数据resolve
                resolve(this.response);
            } else {
                // 抛出错误状态码
                reject(new Error(this.statusText));
            }
        };
        client.send();
    })
}
getJSON('/post.json').then((json) => {
    // Promise状态完成后执行
    console.log('Contents: ' + json);
}, (error) => {
    // Promise状态失败后执行
    console.log('Error: ' + error);
})

Promise.prototype.then()

为Promise实例添加状态改变时的回调函数。

第一个参数是resolved状态的回调函数;第二个参数是rejected状态的回调函数。

then方法返回的是一个新的Promise实例,因此可以采用链式写法。

getJSON('/post.json').then(function(post){
    return getJSON(post.commitURL);
}).then(function(comments){
    console.log('resolved: ' + comments);
}, function(err) {
    console.log('rejected: ' + err);
})

Promise.prototype.catch()

用于指定发生错误时的回调函数。

getJSON('/posts.json').then(posts => {
    // ...
}).catch(error => {
    console.log('Error: ' + error);
})

Promise.prototype.finally()

指定不管Promise对象最后状态如何,都会执行的回调函数。

promise
    .then(result => {...})
    .catch(error => {...})
    .finally(() => {...})

Promise.prototype.all()

将多个Promise实例,包装成一个新的Promise实例。 当实例列表中所有的状态都是resolved时,新实例的状态才会变成resolved,并将实例列表的返回值组成一个数组,传递给新实例的回调函数。 当实例列表中有一个的状态为rejected,新实例的状态就变成rejected,此时第一个被reject的实例的返回值,传递给新实例的回调函数。

const promises = [1, 2, 3].map(id => {
    return getJSON('/post/' + id + '.json');
})
Promise.all(promises).then(posts => {
    // ...
}).catch(err => {
    // ...
})

Promise.prototype.race()

将多个Promise实例,包装成一个新的Promise实例。 当实例列表中一个实例率先改变状态,新实例的状态跟着改变。

Promise.resolve()

将现有对象转为Promise对象。

const jsPromise = Promise.resolve($.ajax('/posts.json'));

Promise.reject()

返回一个新的Promise实例,该实例的状态为rejected。


应用:多个Promise串联

var result1 = loadImg('url1');
var result2 = loadImg('url2');
result1.then(function() {
    console.log('第一张图片加载完成');
    // 将result2返回出去,作为后续链式调用的主体
    return result2;
}).then(function() {
    console.log('第二张图片加载完成');
})

扩展:ES7 Async/Await

异步的同步写法

// 将函数定义为async函数
const load = async function() {
    // 执行loadImg异步函数,loadImg函数必须返回Promise实例
    const result1 = await loadImg('url1');
    console.log(result1);
    const result2 = await loadImg('url2');
    console.log(result2);
}
load()

Promise 前传 - jQuery.Deferred

jQuery 1.5.0版本开始引入的一个新功能——deferred对象。deferred对象的含义就是"延迟"到未来某个点再执行。

deferred对象就是jQuery的回调函数解决方案

var waitHandler = function() {
    // 生成一个Deferred对象
    var dtd = $.Deferred();
    var wait = function(dtd) {
        var task = function() {
            console.log('Finshed');
            if (success) {
                // 执行操作成功的回调
                dtd.resolve();
            } else {
                // 执行操作失败的回调
                dtd.reject();
            }
        }
        // 等待异步队列,然后进入task栈
        setTimeout(task, 1000);
        // 最后将dtd返回出去,供链式调用
        return dtd.promise();   // 返回promise对象,是为了防止链式调用时出现.reject()方法。
    }
    // 进入wait栈
    return wait(dtd);
}
var result = waitHandler();

// then写法
result.then(function() {
    // dtd.resolve()的回调函数
}, function() {
    // dtd.reject()的回调函数
});

// done+fail写法
result
.done(function() { /* dtd.resolve()的回调函数 */ })
.fail(function() { /* dtd.reject()的回调 */ })

参考:ES6 - Promise