如何使用 Promises 实现流畅的接口?

How to implement a fluent interface with Promises?

我想让这段代码起作用

$('start') // push initial value to an array
.addItem(2) // add another value
.printAll() // print everything in array
.delay(2000) // wait x seconds
.addItem(5)
.printAll()
.start(); // execute all the commands before this line

我创建了一个 class 数据数组来保存项目。和 steps 数组来保存操作。然后我使用可链接的承诺来执行它们。这是实现我想要实现的目标的最佳方式吗?我真的需要将操作存储在数组中吗?

 class Sync {

        constructor() {}

        init(startValue) {
            this.data = [startValue];
            this.steps = [];
            return this;
        }

        addItem(value) {
            const append = (v)=>this.data.push(v);
            this._addStep(append, value);
            return this;
        }

        printAll() {
            this._addStep(v=>console.log(v.join()), this.data);
            return this;
        }

        delay(value) {
            this._addStep(window.setTimeout, value);
            return this;
        }

        _addStep(fun, ...args) {
            this.steps.push({
                fun,
                args
            });
        }

        start() {
            let start = Promise.resolve();
            this.steps.forEach(({fun, args})=>{
                start = start.then(()=>{
                    return new Promise(resolve=>{
                        if (fun === window.setTimeout) {
                            setTimeout(resolve, ...args);
                        } else {
                            fun.apply(this, args);
                            resolve();
                        }

                    }
                    );
                }
                );
            }
            );

            return this;
        }
    }
    const lib = new Sync();
    const $ = lib.init.bind(lib);
    $('start')
    .addItem(2)
    .printAll()
    .delay(2000)
    .addItem(5)
    .printAll()
    .start();

虽然你的问题在我看来属于https://codereview.stackexchange.com/,但我试着想出另一种没有 Promises 的实现。它仅适用于闭包和回调:

class Sync {

    constructor() {}

    init(startValue) {
        this.data = [startValue];
        this.steps = [];
        return this;
    }

    addItem(value) {
        const append = v => this.data.push(v);
        this._addStep(append, value);
        return this;
    }

    printAll() {
        this._addStep(v => console.log(v.join()), this.data);
        return this;
    }

    delay(value) {
        this._addStep(window.setTimeout, value);
        return this;
    }

    _addStep(fun, ...args) {
        this.steps.push({
            fun,
            args
        });
    }

    start() {
        let finalFunction;
        this.steps.reverse().forEach(({ fun, args }) => {
            if (fun === window.setTimeout) {
                finalFunction = finalFunction ? encloseFunctionWithArgs(null, null, finalFunction, next => setTimeout(next, ...args)) : null;
            } else {
                finalFunction = encloseFunctionWithArgs(fun, args, finalFunction);
            }

        });
        finalFunction();
        return this;
    }
}

function encloseFunctionWithArgs(fun, args, next, trigger) {
    return function () {
        if (fun)
            fun(args);
        if (next)
            trigger ? trigger(next) : next();
    }
}

const lib = new Sync();
const $ = lib.init.bind(lib);
$('start')
.addItem(2)
.printAll()
.delay(2000)
.addItem(5)
.printAll()
.start();

编辑

我终于实现了你想要的:

const base = {
  init(startValue) {
    this.promise = new Promise(resolve => this.start = resolve).then(() => [startValue]);
    return this;
  },

  addItem(value) {
    this.promise = this.promise.then(v => [...v, value]);
    return this;
  },

  printAll() {
    this.promise.then(v => v.join()).then(console.log);
    return this;
  },

  delay(value) {
    this.promise = this.promise.then(v => new Promise(resolve => setTimeout(() => resolve(v), value)));
    return this;
  }
}

const factory = base => arg => Object.create(base).init(arg);

const $ = factory(base);

$('start')
.addItem(2)
.printAll()
.delay(2000)
.addItem(5)
.printAll()
.start();