Promise 怎样封装?
发布于 5 年前 作者 houkaihua888 7483 次浏览 来自 问答

新人入门,请多多指教。 生成一个随机数,如果大于0.9则返回成功,否则返回失败,并重新生成随机数,直到返回成功为止。 怎样用Promise 来写? (相当于请求一个网址,成功返回请求成功,失败则继续请求,直到成功为止)如果失败后等待一秒再请求呢,该咋样写?

6 回复

我用的是bluebird

你的问题好像和Promise关系不大,简单的回调就搞定了。Promise是为异步编程提供一种同步抽象,就是可以有返回值和catch异常。一般在一个想对复杂的异步流程里面会非常有用,对于这种,我一般会用组合的方式,就是前一个promise的返回作为下一个的输入,然后在最后面catch异常。如果你能将promise和generator结和一下,那写出的代码想对就比较优雅了。

之前的代码delay有问题,特地重构了下。假设有一个HTTP请求

function fetchComList() {
    return new Promise(function (resolve, reject) {
        var xhr = new XMLHttpRequest();
        xhr.open('GET', '/companies', true);
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                xhr.status === 200 ? resolve(xhr.responseText) : reject(xhr.responseText);
            }
        };
        xhr.send();
    });
}

Promise Retry

function promiseRetry(opts) {
    var originalFn;

    //设置
    opts = Object.assign({
        times: 0,
        delay: 0
    }, opts);

    return function exec(fn) {
        if (!originalFn) originalFn = fn;

        return fn().catch(function (error) {
            if (opts.times-- <= 0)return Promise.reject(error);
            return exec(delay);
        });
    };

    //延时处理
    function delay() {
        return new Promise(function (resolve) {
            setTimeout(function () {
                resolve(originalFn());
            }, opts.delay);
        })
    }
}

var promiseRetryInstance = promiseRetry({times: 2, delay: 2000});

promiseRetryInstance(fetchComList).then(function (data) {
    console.log(data)
}).catch(function (err) {
    console.log(err);
});

Rxjs Retry

@htoooth 提到的Rxjs版本

function rxRetry(fn, opts) {
    opts = Object.assign({
        times: 0,
        delay: 0
    }, opts);

    return Rx.Observable
            .defer(function () {
                return fn();
            })
            .retryWhen(function (errs) {
                return errs
                        .zip(Rx.Observable.range(1, opts.times), function (x, y) {
                            return y
                        })
                        .flatMap(function () {
                            return Rx.Observable.timer(opts.delay);
                        });
            })
}

rxRetry(fetchComList, {times: 2, delay: 2000}).subscribe(function (data) {
    console.log(data);
}, function (err) {
    console.log(err)
});

楼上已经帮你回答了,不过同步的东西为什么要封装成promise

import Rx from "rx";
let count = 0;
const random = (cb) => {
    console.log("one" + (count++));
    let result = Math.random();
    if (result > 0.9) {
        cb(null, result);
    } else {
        cb("error");
    }
};
const source = Rx.Observable.defer(() => Rx.Observable.fromNodeCallback(random)())
    .retryWhen(err => err
        .zip(Rx.Observable.range(1, 3), (x, y) => y)
        .flatMap(x => Rx.Observable.timer(1000))
    );

const subscription = source.subscribe(
    function(x) {
        console.log('Next: ' + x);
    },
    function(err) {
        console.log('Error: ' + count);
    },
    function() {
        console.log('Completed' + count);
    });

这种情况就很种使用,rxjs,而不是 promise。

var Promise = require('bluebird');
function request() {
  return new Promise(function (resovle, reject) {
    setTimeout(function() {
      var num = Math.random();
      if(num > 0.8){
        resovle(num);
      }else{
        reject(num);
      }
    },1000);
  })
}
function digui() {
  return request().then(function(res) {
    console.log('成功 ' + res);
    return;
  }).catch(function(err) {
    console.log('失败 ' + err);
    return digui();
  })
}
digui().done();
回到顶部