Promise 与定时器

2019-9-12 hubo Web前端

介绍 Promise 基础的文章已经非常多了,在这里就不再讲解 Promise 本身的用法。本文主要介绍利用 Promise 的特性改良异步 Timer 的一种思路。

在产品中,异步加载资源的时候,有时会有一种业务需求,需要执行某个任务,直到任务返回 false 或者超过某个时间限制。

例如,存在类似这样的代码:


qboot.await(function() {

    return hao360.g("channelloading-" + channel);

},

function() {

    setTimeout(function() {

        if (hao360.g("channelview-" + channel).innerHTML.replace(/^[\s\xa0\u3000]+|[\u3000\xa0\s]+$/g, "") == "") {

            hao360.g("channelloading-" + channel).style.display = "block";

        }

    },

    1000);

},

null, 100, 100);



这里的 qboot.await 实际上是一个异步的 timer,由于导航网页上的部分内容是异步加载的,因此用 qboot.await 来确保操作相关 DOM 的时候内容已经加载完毕。



qboot 的具体代码在 github 上可以找到。这里截取其中的片段:

/**

 * 轮询执行某个task,直到task返回false或者超过轮询最大次数上限

 * 如果成功超过轮询上限,执行complete,否则执行abort

 * @param task 轮询的任务

 * @param step 轮询间隔,以毫秒为单位

 * @param max 最大轮询次数

 * @param complete 超过最大次数,轮询成功

 * @param abort task返回false,轮询被中断

 */

poll : function(task, step, max, complete, abort){

    step = step || 100;

    if(max == null) max = Infinity;     

    if(max <= 0){

        complete && complete();

        return;

    } 


    if(task() !== false){

        setTimeout(function(){

            qboot.poll(task, step, max-1, complete, abort);

        }, step);

    }else{

        abort && abort();

    }

},

/**

 * 等待直到cond条件为true执行success

 * 如果等待次数超过max,则执行failer

 * @param cond await条件,返回true则执行success,否则继续等待,直到超过等待次数max,执行failer

 * @param success await成功

 * @param failer await失败

 * @param step 时间间隔

 * @param max 最大次数

 */

await : function(cond, success, failer, step, max){     

    qboot.poll(function(){

        if(cond()){

            success();

            return false;

        }

        return true;

    }, step, max, failer);

},




await 方法虽好,但是不够语义化,在这个支持 Promise 的时代,实现这个需求,我们可以有更好的设计思路,产生更加 语义化  API:

let promise = wait.every(100).before(10000).until(function(){

    return hao360.g("channelloading-" + channel) || false;

});


promise.then(function(channel){

    //do sth.

});




wait-promise

我们可以基于 Promise 实现一套优雅的 API,把它封装成 wait-promise 库。

根据常见应用场景设计如下 API

check

wait.check(condition)

check 总是返回一个 promise,如果 condition 抛出未处理的异常或者返回一个 false 值,那么 promise 的状态为 reject,否则 resolve promise

例如:

let i = 1;

let promise = wait.check(function(){

  return i < 1;

});

promise.catch(function(err){

  console.log(err.message); //will be check failed

});

until

wait.until(condition)

until 每隔若干时间间隔(默认为100ms),检查一次 condition,直到当前 condition 不抛异常也不返回 false 值为止,满足条件后将 promise 的状态置为 resolve

例如:

let i = 0;

let promise = wait.until(function(){

    return ++i >= 10;

});

promise.then(function(){

    console.log(i); //i will be 10

});




ES7 的用法:

let until = wait.until;


async function foo(){

    let i = 0;


    await until(() => ++i > 10);

    bar();

}

till

wait.till(condition)

 until 类似,不同之处在于 condition 返回 true 的时候 till  promise 的状态置为 resolve。同样与 until 相反,如果 till  condition 抛异常, promise 的状态为 reject

例如(通常情形下和 until 用法一样):

let i = 0;

let promise = wait.till(function(){

    return ++i >= 10;

});

promise.then(function(){

    console.log(i); //i will be 10

});




before

wait.before(millisec).until(condition)

before 通常和 until 组合使用,给 until 轮询限制一个最长时间,超过时间之后,如果 condition 还是抛异常或者返回 false,则将 promise 的状态置成 reject

例如:

let i = 0;

let promise = wait.before(200).until(function(){

    return ++i >= 10;

});

promise.catch(function(err){

    console.log(i, err.message); //2 check failed

});




通常我们可以用来判断资源是否加载成功(包含超时):

var promise = wait.before(5000).until(function(){

  return typeof Babel !== "undefined";

});


promise.then(function(){

  code = Babel.transform(code, { presets: ["es2015-loose", "react", "stage-0"] }).code;

}).catch(function(){

  console.error("Cannot load babeljs.");

});




after

wait.after(millisec).check(condition)

after 通常和 check 组合使用,超过一定时间之后再执行 condition 检查。

例如:

let i = 1;

setTimeout(function(){

    ++i;

}, 0); 

let promise = wait.after(1000).check(function(){

    return i > 200;

});

after 也可以和 util 组合使用,因为 wait.util 第一次总是会尽快执行(然后才是每经过固定时间间隔执行一次),所以使用 after 可以让 until 第一次执行也延迟。

介绍 Promise 基础的文章已经非常多了,在这里就不再讲解 Promise 本身的用法。本文主要介绍利用 Promise 的特性改良异步 Timer 的一种思路。

在产品中,异步加载资源的时候,有时会有一种业务需求,需要执行某个任务,直到任务返回 false 或者超过某个时间限制。

例如,在 360网址导航 中,存在类似这样的代码:

qboot.await(function() {

    return hao360.g("channelloading-" + channel);

},

function() {

    setTimeout(function() {

        if (hao360.g("channelview-" + channel).innerHTML.replace(/^[\s\xa0\u3000]+|[\u3000\xa0\s]+$/g, "") == "") {

            hao360.g("channelloading-" + channel).style.display = "block";

        }

    },

    1000);

},

null, 100, 100);





这里的 qboot.await 实际上是一个异步的 timer,由于导航网页上的部分内容是异步加载的,因此用 qboot.await 来确保操作相关 DOM 的时候内容已经加载完毕。

qboot 的具体代码在 github 上可以找到。这里截取其中的片段:

/**

 * 轮询执行某个task,直到task返回false或者超过轮询最大次数上限

 * 如果成功超过轮询上限,执行complete,否则执行abort

 * @param task 轮询的任务

 * @param step 轮询间隔,以毫秒为单位

 * @param max 最大轮询次数

 * @param complete 超过最大次数,轮询成功

 * @param abort task返回false,轮询被中断

 */

poll : function(task, step, max, complete, abort){

    step = step || 100;

    if(max == null) max = Infinity;     

    if(max <= 0){

        complete && complete();

        return;

    } 


    if(task() !== false){

        setTimeout(function(){

            qboot.poll(task, step, max-1, complete, abort);

        }, step);

    }else{

        abort && abort();

    }

},





/**

 * 等待直到cond条件为true执行success

 * 如果等待次数超过max,则执行failer

 * @param cond await条件,返回true则执行success,否则继续等待,直到超过等待次数max,执行failer

 * @param success await成功

 * @param failer await失败

 * @param step 时间间隔

 * @param max 最大次数

 */

await : function(cond, success, failer, step, max){     

    qboot.poll(function(){

        if(cond()){

            success();

            return false;

        }

        return true;

    }, step, max, failer);

},

await 方法虽好,但是不够语义化,在这个支持 Promise 的时代,实现这个需求,我们可以有更好的设计思路,产生更加 语义化  API:

let promise = wait.every(100).before(10000).until(function(){

    return hao360.g("channelloading-" + channel) || false;

});


promise.then(function(channel){

    //do sth.

});

wait-promise

我们可以基于 Promise 实现一套优雅的 API,把它封装成 wait-promise 库。

根据常见应用场景设计如下 API





check

wait.check(condition)

check 总是返回一个 promise,如果 condition 抛出未处理的异常或者返回一个 false 值,那么 promise 的状态为 reject,否则 resolve promise

例如:

let i = 1;

let promise = wait.check(function(){

  return i < 1;

});

promise.catch(function(err){

  console.log(err.message); //will be check failed

});

until

wait.until(condition)

until 每隔若干时间间隔(默认为100ms),检查一次 condition,直到当前 condition 不抛异常也不返回 false 值为止,满足条件后将 promise 的状态置为 resolve

例如:

let i = 0;

let promise = wait.until(function(){

    return ++i >= 10;

});

promise.then(function(){

    console.log(i); //i will be 10

});

ES7 的用法:

let until = wait.until;


async function foo(){

    let i = 0;


    await until(() => ++i > 10);

    bar();

}






till

wait.till(condition)

 until 类似,不同之处在于 condition 返回 true 的时候 till  promise 的状态置为 resolve。同样与 until 相反,如果 till  condition 抛异常, promise 的状态为 reject

例如(通常情形下和 until 用法一样):

let i = 0;

let promise = wait.till(function(){

    return ++i >= 10;

});

promise.then(function(){

    console.log(i); //i will be 10

});

before

wait.before(millisec).until(condition)

before 通常和 until 组合使用,给 until 轮询限制一个最长时间,超过时间之后,如果 condition 还是抛异常或者返回 false,则将 promise 的状态置成 reject

例如:

let i = 0;

let promise = wait.before(200).until(function(){

    return ++i >= 10;

});

promise.catch(function(err){

    console.log(i, err.message); //2 check failed

});

通常我们可以用来判断资源是否加载成功(包含超时):

var promise = wait.before(5000).until(function(){

  return typeof Babel !== "undefined";

});


promise.then(function(){

  code = Babel.transform(code, { presets: ["es2015-loose", "react", "stage-0"] }).code;

}).catch(function(){

  console.error("Cannot load babeljs.");

});




after

wait.after(millisec).check(condition)

after 通常和 check 组合使用,超过一定时间之后再执行 condition 检查。

例如:

let i = 1;

setTimeout(function(){

    ++i;

}, 0); 

let promise = wait.after(1000).check(function(){

    return i > 200;

});

after 也可以和 util 组合使用,因为 wait.util 第一次总是会尽快执行(然后才是每经过固定时间间隔执行一次),所以使用 after 可以让 until 第一次执行也延迟。

网站备案号:京ICP备11043289号-1 北京市公安局网络备案 海1101084571
版权所有 北京育灵童科技发展有限公司 Copyright © 2002-2024 www.elight.cn, All Rights Reserved