Keep moving just play & have fun

js异步事件处理

2018-03-28
May

阅读:

Web

js中的异步事件处理


ES6诞生以前,异步编程的方法主要有以下几种:回调函数、事件监听、发布/订阅、Promise对象;ES6中引入了Generator函数;ES7中,async/await将异步编程带入了一个全新的阶段。

文章将对这些异步操作的使用和优缺点进行进一步的比较和分析。本文内容部分摘抄自《Mozilla Promise Reference》

1.1 什么是Promise

Promise是抽象异步处理对象以及对其进行各种操作的组件。

// 使用了回调函数的异步处理
getAsync("fileA.txt", function(error, result) {
    if(error) { // 取得失败时的处理
        throw error;
    }
    // 成功时的处理
})

Node.js规定在javascript的回调函数中的第一个参数为Error对象。

下面看个使用了Promise进行异步处理的例子:

var promise = getAsyncPromise("fileA.txt"); // 返回Promise对象
promise.then(function(result) {
    // 成功时的处理
}).catch(function(error) {
    // 失败时的处理
})

两者比较,回调函数方式可以自己定义回调函数的采纳数,而使用promise对象处理的时候,除了promise规定的thencatch以外的方法都是不可以使用的,必须严格遵守固定、统一的编程方式来写代码。

所以,promise的功能就是可以将复杂的异步处理轻松的进行模式化。

1.1.1 Promise的语法

Promise的使用大概有以下三种类型:

Constructor

Promise类似于XMLHttpRequest, 从构造函数Promise创建一个新的promise实例

var promise = new Promise(function(resolve, reject) {
    // 处理结束后,调用resolve或reject
})
Instance Method

对通过new生成的promise对象,可以使用promise.then() 方法来调用resolvereject的回调函数。

promise.then(onFulfilled, onRejected)

resolve成功 onFulfilled会被调用 reject失败 onRejected会被调用

promise.then成功和失败时都可以使用。在只想对异常进行处理时,可以采用promise.then(undefined, onRejected)这种方式,只指定reject时的回调函数。不过这种情况下,promise.catch(onRejected)是个更好的选择。

promise.catch(onRejected);
Static Method

Promise包括一些静态方法如Promise.all()Promise.resolve()等。

1.1.2 Promise的三种状态
状态 描述
pending 初始状态,既不是成功也不是失败,也就是promise实例刚被创建的初始状态。
fulfilled resolve(成功),此时会调用onFulfilled
rejected reject(失败), 此时会调用onRejected
1.1.3 Promise示例代码

function getURL(URL) {
    var promise = new Promise(function (resolve, reject) {
        var req = new XMLHttpRequest();
        req.open('GET', URL, true);
        req.onload = function () {
            if(req.status == 200) {
                resolve(req.responseText);
            }
             else{
                 reject(new Error(req.statusText));
             }
        };
        req.onerror = function() {
            reject(new Error(req.statusText));
        };
        req.send();
    })
}

var URL = 'http://xxx.xx.txt';
getURL(URL).then(function onFulfilled(value) {
    console.log(value);
}).catch(function onRejected(error) {
    console.error(error);
})

1.2 Promise.prototype

Promise实例继承自Promise.prototype. 你可以通过构造器的原型对象在所有的Promise实例上添加属性或方法。

Promise.prototype.constructor

Promise.prototype.constructor表示Promise的构造函数的原型,以便在其原型上放置then()catch()finally()方法。

Promise.prototype.then(onFulfilled, onRejected)

为promise添加成功或者失败处理,同时返回一个新的包含解析过后的的值或者处理函数的promise,或者这个原始的未被处理的promise。

Promise.prototype.catch(onRejected)

为promise添加失败的回调处理,如果这个回调函数被调用了,则返回一个包含回调返回值的新的promise,如果这个promise没被处理,则返回原始的值。

Promise.prototype.finally(onFinally)

为promise添加处理,如果原始的promise对象已经被解析,则返回解析后的promise。无论promise是什么状态,这个处理函数都会被执行。

Promise的静态方法

Promise.resolve

一般情况下,我们会使用new Promise()来创建promise对象,我们也可以使用Promise.resolvePromise.reject()

例如Promise.resolve(42),可以认为是以下代码的语法糖:

new Promise(resolve => {
    resolve(42);
})


Promise.all(iterable)

当iterable参数中所有的promises都被resolve时,或参数中不包含promises的时候,Promise.all(iterable)会返回一个单一的Promise。当iterable中有一个promise返回拒绝,all()方法会立即终止并返回第一个被reject的promise对象。

var promise1 = Promise.resolve(3);
var promise2 = 42;
var promise3 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 100, 'foo');
})

Promise.all([promise1, promise2, promise3]).then(function(values) {
    console.log(values);// 3, 42, foo
})

Promise.race(iterable)

Promise.race(iterable)方法返回iterable参数中最先被resolve或者reject的promise对象,包括返回值或者失败原因。

var promise1 = new Promise((resolve, reject) => {
    setTimeout(resolve, 300, 'one');
});

var promise2 = new Promise((resolve, reject) => {
    setTimeout(resolve, 100, 'two');
});

Promise.race([promise1, promise2]).then(result => {
    console.log(result);// expected 'two'
})

上一篇 js设计模式

Comments

Content