[手工实现]1. Promise 详解剖析

实现目标

  1. 基础功能——then函数异步回调(不带链式调用功能)
  2. 基础功能——链式调用功能
  3. 基础功能——catch、finally函数功能
  4. 高级功能——Promise.resolve、Promise.reject
  5. 高级功能——Promise.all、Promise.race、Promise.allSettled
  6. 完整代码示例,并执行case与标准Promise比较

Promise的基本说明

Promise 对象是一个代理对象(代理一个值),被代理的值在Promise对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的promise对象

一个 Promise有以下几种状态:

  • pending: 初始状态,既不是成功,也不是失败状态。
  • fulfilled: 意味着操作成功完成。
  • rejected: 意味着操作失败。

pending 状态的 Promise 对象可能会变为fulfilled 状态并传递一个值给相应的状态处理方法,也可能变为失败状态(rejected)并传递失败信息。当其中任一种情况出现时,Promise 对象的 then 方法绑定的处理方法(handlers )就会被调用(then方法包含两个参数:onfulfilled 和 onrejected,它们都是 Function 类型。当Promise状态为fulfilled时,调用 then 的 onfulfilled 方法,当Promise状态为rejected时,调用 then 的 onrejected 方法, 所以在异步操作的完成和绑定处理方法之间不存在竞争)。

image.png

基础功能

Promise基本构造

/**
*@Promise的三种状态枚举
*/
enum PromiseState {
  pending,
  fulfilled,
  rejected
}
// Promise构造函数传入的执行器类型
type PromiseExecutor<T, E> = (resolve: PromiseResolve<T>, reject: PromiseReject<E>) => unknown;
type PromiseResolve<T> = (value?: T) => void;
type PromiseReject<T> = (error?: T) => void;
//Promise then函数onFulfilled参数类型
type PromiseThenOnFulfilled<T> = (value: T) => Promise | unknown;
//Promise then函数onRejected参数类型
type PromiseThenOnRejected<T> = (error: T) => Promise | unknown;
//Promise catch函数onExcepted参数类型
type PromiseCatchOnExcepted<T> = (error: T) => Promise | unknown;
type PromiseOnFinal = () => unknown;

export class Promise<T = unknown, E = unknown> {
  
  public readonly name = Symbol('Promise');
  // 标识当前实例的状态,初始化为pending
  private state: PromiseState = PromiseState.pending;
  // 成功后数据的存储
  private value!: T;
  // 失败或异常后数据的存储
  private error!: E;
  // then成功回调参数的存储
  private onFulfilled?: PromiseThenOnFulfilled<T>;
  // then失败回调参数的存储
  private onRejected?: PromiseThenOnRejected<E>;
  // catch函数参数的存储
  private onExcepted?: PromiseCatchOnExcepted<E>;
  // finally函数参数的存储
  private onFinal?: PromiseOnFinal;
  // nextPromise, 表明当then\catch\finally函数被调用后,返回的一个新的Promise实例。实现链式调用
  private nextPromise?: Promise;
  // 构造函数
  constructor(executor: PromiseExecutor<T, E> = () => { }) {

  }
  // then函数,当实例状态变更为fulfilled时,第一个函数参数被回调,当状态变更为rejected时,第二个函数参数被回调。如果一个参数都没有传入,状态会被派生至下次回调函数的出现。
  public then(onFulfilled?: PromiseThenOnFulfilled<T>, onRejected?: PromiseThenOnRejected<E>) {

  }
  // catch函数,当实例状态变更为rejected并且then函数没有传入第二个参数时,此函数中传入的参数将被回调。
  public catch(onExcepted?: PromiseCatchOnExcepted<E>) {

  }
  // finally函数,当实例状态变更为成功后失败后,该函数中传入的回调参数都会被调用。
  public finally(onFinal?: PromiseOnFinal) {

  }

}

then函数异步回调

1.Promise函数被创建时,传入的回调函数即会被调用,所以有如下代码

//some code...
// 实例初始化时即调用
  constructor(executor: PromiseExecutor<T, E> = () => { }) {
    executor(this.resolve, this.reject)
  }
// resolve被调用时,将值保存到实例中,并且更改状态为fulfilled
  private resolve = (value?: T) => {
    this.value = value as T;
    this.setState(PromiseState.fulfilled);
  }
// reject被调用时,将值保存到实例中,并且更改状态为rejected
  private reject = (error?: E) => {
    this.error = error as E;
    this.setState(PromiseState.rejected);
  }
// 统一状态设置入口,以便状态被改变时做一些事情
private setState = (state: PromiseState) => {
      this.state = state;
  }
//some code...
  1. then函数被调用时,将传入的函数保存到实例中,以便状态变更后回调
public then(onFulfilled?: PromiseThenOnFulfilled<T>, onRejected?: PromiseThenOnRejected<E>) {
    this.onFulfilled = onFulfilled;
    this.onRejected = onRejected;
  }
  1. 当状态被变更,触发传入的回调函数,修改之前的setState函数(暂不处理then函数传不传参的情况)
private setState = (state: PromiseState) => {
    this.state = state;
    if (state === PromiseState.fulfilled) {
        this.onFulfilled(this.value);
    }
    else if (state === PromiseState.rejected) {
        this.onRejected(this.error);
    }
}

链式回调功能实现

要实现链式回调功能,方法函数必须返回一个同类型的实例。并且,由于Promise的特性,下一个then等函数中回调函数的调用时机,也要根据当前实例then等函数返回的状态而决定。所以才有了第一段代码中nextPromise属性存在的意义。当then等函数被调用时,返回准备好的下一个新的Promise实例,此实例的状态是初始状态,当当前实例的onFulfilled/onRejected/onExcepted被调用后,可以知道其返回值是否为Promise,从而判断该如何将当前状态托管到下一个Promise。

  1. 改造then函数,使其返回一个新的Promise实例
public then(onFulfilled?: PromiseThenOnFulfilled<T>, onRejected?: PromiseThenOnRejected<E>) {
    this.onFulfilled = onFulfilled;
    this.onRejected = onRejected;
  // 返回一个新的Promise实例,下一个then或其他方法的调用,将会在此实例上进行
    return this.next();
  }

private next() {
  // 返回前检查下nextPromise是否被有值
    this.checkNextPromise();
    return this.nextPromise as Promise;
  }

private checkNextPromise(np: Promise | undefined = undefined): np is Promise {
  // 一旦发现nextPromise还没有值,就给他赋一个新的Promise实例上去
    if (!this.nextPromise) {
      this.nextPromise = new Promise(); // 没有传入任何参数的Promise的状态是会处于pending中的
    }
    return true;
  }
  1. 改造setState,在状态被设置的时候,调用相应的回调函数,并且根据回调函数的返回值类型来设置nextPromise
private resolve = (value?: T) => {
    this.value = value as T;
  // 将调用setState函数的时机改为异步调用
    setTimeout(this.setState, 0, PromiseState.fulfilled);
  }

  private reject = (error?: E) => {
    this.error = error as E;
  // 将调用setState函数的时机改为异步调用
    setTimeout(this.setState, 0, PromiseState.rejected);
  }

private setState = (state: PromiseState) => {
    const { nextPromise } = this;
    // 理论上是不会存在nextPromise没有值的,因为setState函数的调用一定在nextPromise被初始化之后
    if (!nextPromise) {
      return;
    }

    this.state = state;

    if (state === PromiseState.fulfilled) {
        this.handleFulfilled(nextPromise);
      }
  }

private handleFulfilled(next: Promise) {
    if (this.onFulfilled) {
// 如果有onFulfilled回调,则直接回调其函数,并且检查返回值是否是Promise
      this.checkCallResult(this.onFulfilled(this.value), next);
    }
    else {
// 如果没有,则将成功状态托管给下一个Promise,等待数据被取用
      next.resolve(this.value);
    }
  }

private checkCallResult(result: Promise | unknown, next: Promise) {
    if (result instanceof Promise) {
  // 如果返回值是Promise实例,则将生成的新Promise代理到返回的Promise上
      Promise.transmit(result, next);
    }
    else {
      next.resolve();
    }
  }

/** @static */
  public static transmit(from: Promise, to: Promise) {
    from.resolve = to.resolve;
    from.reject = to.reject;
  }

完善基础功能,实现catch、finally函数

catch函数的回调是在当实例状态变更为失败的时候并且then函数没有传入第二个值时才会被调用。调用后同then函数一样,链式传递。
finally函数的回调是在当实例状态非pending时,在最后始终会调用的一个回调。调用后同then函数一样,链式传递。

constructor(executor: PromiseExecutor<T, E> = () => { }) {
// Promise标准中,executor如果发生异常,也算作是rejected,所以需要捕获异常来达到目的
  try {
      executor(this.resolve, this.reject);
    } catch (error) {
      this.reject(error);
    }
  }

public catch(onExcepted?: PromiseCatchOnExcepted<E>) {
    this.onExcepted = onExcepted;
    return this.next();
  }

  public finally(onFinal?: PromiseOnFinal) {
    this.onFinal = onFinal;
    return this.next();
  }

private setState = (state: PromiseState) => {
    const { nextPromise } = this;

    if (!nextPromise) {
      return;
    }

    this.state = state;

// 不论是reject被调用还是直接发生throw,失败的回调函数都会被调用
    try {
      if (state === PromiseState.fulfilled) {
        this.handleFulfilled(nextPromise);
      }
      else if (state === PromiseState.rejected) {
        this.handleError(nextPromise);
      }
    } catch (error) {
      this.error = error;
      this.handleError(nextPromise);
    }
  }

private handleError(next: Promise) {
    if (this.onRejected) {
      this.checkCallResult(this.onRejected(this.error), next);
    }
    else if (this.onExcepted) {
      this.checkCallResult(this.onExcepted(this.error), next);
    }
    else if (this.onFinal) {
      this.onFinal();
      next.reject(this.error);
    }
    else {
      next.reject(this.error);
    }
  }

resolve和reject功能的实现

public static resolve<V>(value?: V | Promise) {
// 传入参数如果是Promise,则直接返回,如果是其他,则返回一个新的Promise,并且回调实例的resolve
    return value instanceof Promise ? value : new Promise((r) => r(value))
  }

  public static reject<R>(reason?: R) {
    return new Promise((r, j) => {
      j(reason)
    })
  }

Promise.all、Promise.race、Promise.allSettled功能实现

public static allSettled<R, E = R>(iterable: Promise<R, E>[]) {
    let complates: Array<R | E> = [];
    let completedNumber = 0;
    const result = new Promise();
    iterable.forEach((p, i) => {
      p.then(d => {
        complates[i] = d;
        completedNumber++;
        if (completedNumber === iterable.length) {
          result.resolve(complates);
        }
      }, e => {
        complates[i] = e;
        completedNumber++;
        if (completedNumber === iterable.length) {
          result.resolve(complates);
        }
      });
    })

    return result as Promise<Array<R | E>, E>;
  }

  public static all<R, E>(iterable: Promise<R, E>[] | Promise<R, E> | string) {
    let succs: R[] = [];
    let completedNumber = 0;
    const result = new Promise();
    const resolve = () => result.resolve(succs);
    const reject = (reason: E) => result.reject(reason);

    if (iterable instanceof Promise) {
      iterable.then(d => {
        succs.push(d)
        resolve();
      }, e => reject(e));
    }
    else if (typeof iterable === 'string') {
      succs = iterable.split('') as any[];
      setTimeout(() => resolve());
    }
    else if (iterable instanceof Array) {
      iterable.forEach((p, i) => {
        p.then(d => {
          completedNumber++;
          succs[i] = d;
          if (completedNumber === iterable.length) {
            resolve();
          }
        }, e => reject(e));
      })
    }

    return result as Promise<R[], E>;
  }

  public static race<T, E>(iterable: Promise[]) {
    const result = new Promise();

    iterable.forEach(item => {
      item.then(d => result.state === PromiseState.pending && result.resolve(d), e => result.state === PromiseState.pending && result.reject(e))
    })

    return result as Promise<T, E>;
  }

完整代码

enum PromiseState {
  pending,
  fulfilled,
  rejected
}
type PromiseExecutor<T, E> = (resolve: PromiseResolve<T>, reject: PromiseReject<E>) => unknown;
type PromiseResolve<T> = (value?: T) => void;
type PromiseReject<T> = (error?: T) => void;
type PromiseThenOnFulfilled<T> = (value: T) => Promise | unknown;
type PromiseThenOnRejected<T> = (error: T) => Promise | unknown;
type PromiseCatchOnExcepted<T> = (error: T) => Promise | unknown;
type PromiseOnFinal = () => unknown;

export class Promise<T = unknown, E = unknown> {

  public readonly name = Symbol('Promise');
  private state: PromiseState = PromiseState.pending;
  private value!: T;
  private error!: E;
  private onFulfilled?: PromiseThenOnFulfilled<T>;
  private onRejected?: PromiseThenOnRejected<E>;
  private onExcepted?: PromiseCatchOnExcepted<E>;
  private onFinal?: PromiseOnFinal;
  private nextPromise?: Promise;

  constructor(executor: PromiseExecutor<T, E> = () => { }) {
    this.handleExecutor(executor);
  }

  private handleExecutor(executor: PromiseExecutor<T, E>) {
    try {
      executor(this.resolve, this.reject);
    } catch (error) {
      this.reject(error);
    }
  }

  private handleFulfilled(next: Promise) {
    if (this.onFulfilled) {
      this.checkCallResult(this.onFulfilled(this.value), next);
    }
    else if (this.onFinal) {
      this.onFinal();
      next.resolve(this.value);
    }
    else {
      next.resolve(this.value);
    }
  }

  private handleError(next: Promise) {
    if (this.onRejected) {
      this.checkCallResult(this.onRejected(this.error), next);
    }
    else if (this.onExcepted) {
      this.checkCallResult(this.onExcepted(this.error), next);
    }
    else if (this.onFinal) {
      this.onFinal();
      next.reject(this.error);
    }
    else {
      next.reject(this.error);
    }
  }

  private setState = (state: PromiseState) => {
    const { nextPromise } = this;

    if (!nextPromise) {
      return;
    }

    this.state = state;

    try {
      if (state === PromiseState.fulfilled) {
        this.handleFulfilled(nextPromise);
      }
      else if (state === PromiseState.rejected) {
        this.handleError(nextPromise);
      }
    } catch (error) {
      this.error = error;
      this.handleError(nextPromise);
    }
  }

  private checkCallResult(result: Promise | unknown, next: Promise) {
    if (result instanceof Promise) {
      Promise.transmit(result, next);
    }
    else {
      next.resolve();
    }
  }

  private resolve = (value?: T) => {
    this.value = value as T;
    setTimeout(this.setState, 0, PromiseState.fulfilled);
  }

  private reject = (error?: E) => {
    this.error = error as E;
    setTimeout(this.setState, 0, PromiseState.rejected);
  }

  private next() {
    this.checkNextPromise();
    return this.nextPromise as Promise;
  }

  private checkNextPromise(np: Promise | undefined = undefined): np is Promise {
    if (!this.nextPromise) {
      this.nextPromise = new Promise(() => { });
    }
    return true;
  }

  public then(onFulfilled?: PromiseThenOnFulfilled<T>, onRejected?: PromiseThenOnRejected<E>) {
    this.onFulfilled = onFulfilled;
    this.onRejected = onRejected;
    return this.next();
  }

  public catch(onExcepted?: PromiseCatchOnExcepted<E>) {
    this.onExcepted = onExcepted;
    return this.next();
  }

  public finally(onFinal?: PromiseOnFinal) {
    this.onFinal = onFinal;
    return this.next();
  }

  /** @static */
  public static transmit(from: Promise, to: Promise) {
    from.resolve = to.resolve;
    from.reject = to.reject;
  }

  public static resolve<V>(value?: V | Promise) {
    return value instanceof Promise ? value : new Promise((r) => r(value))
  }

  public static reject<R>(reason?: R) {
    return new Promise((r, j) => {
      j(reason)
    })
  }

  public static allSettled<R, E = R>(iterable: Promise<R, E>[]) {
    let complates: Array<R | E> = [];
    let completedNumber = 0;
    const result = new Promise();
    iterable.forEach((p, i) => {
      p.then(d => {
        complates[i] = d;
        completedNumber++;
        if (completedNumber === iterable.length) {
          result.resolve(complates);
        }
      }, e => {
        complates[i] = e;
        completedNumber++;
        if (completedNumber === iterable.length) {
          result.resolve(complates);
        }
      });
    })

    return result as Promise<Array<R | E>, E>;
  }

  public static all<R, E>(iterable: Promise<R, E>[] | Promise<R, E> | string) {
    let succs: R[] = [];
    let completedNumber = 0;
    const result = new Promise();
    const resolve = () => result.resolve(succs);
    const reject = (reason: E) => result.reject(reason);

    if (iterable instanceof Promise) {
      iterable.then(d => {
        succs.push(d)
        resolve();
      }, e => reject(e));
    }
    else if (typeof iterable === 'string') {
      succs = iterable.split('') as any[];
      setTimeout(() => resolve());
    }
    else if (iterable instanceof Array) {
      iterable.forEach((p, i) => {
        p.then(d => {
          completedNumber++;
          succs[i] = d;
          if (completedNumber === iterable.length) {
            resolve();
          }
        }, e => reject(e));
      })
    }

    return result as Promise<R[], E>;
  }

  public static race<T, E>(iterable: Promise[]) {
    const result = new Promise();

    iterable.forEach(item => {
      item.then(d => result.state === PromiseState.pending && result.resolve(d), e => result.state === PromiseState.pending && result.reject(e))
    })

    return result as Promise<T, E>;
  }

}

/** case */

// new Promise((resolve, reject) => {
//   console.log('start')
//   // resolve(1)
//   setTimeout(() => {
//     resolve(123)
//   }, 1000)
// }).then((data) => {
//   console.log(data)
//   return new Promise((r) => setTimeout(() => r(2), 2000))
// }).then((data) => {
//   console.log(data)
// }).then(() => {
//   console.log(22222)
//   return new Promise((r) => r('eeeeee'))
// }).then().then((data) => {
//   console.log(data)
//   console.log('end')
// })

// new Promise((resolve, reject) => {
//   setTimeout(() => resolve(1), 1000);
//   // reject(1)
// }).then((data) => {
//   console.log(data)
//   return new Promise((r) => {
//     setTimeout(() => r(1.1), 1000)
//   })
// }).finally(() => {
//   console.log('finally')
//   console.log(123)
// }).then((data) => {
//   console.log('then')
//   console.log(data);
// }).catch((e) => {
//   console.log('catch')
//   console.log(e);
// }).then((data) => {
//   console.log('then: last')
//   console.log(data)
// })

// new Promise((resolve, reject) => {
//   // setTimeout(() => resolve(1), 1000);
//   setTimeout(() => reject(2), 1000);
// }).then((data) => {
//   console.log(data)
// }).catch((e) => {
//   console.log(e)
//   return new Promise((r, j) => {
//     setTimeout(() => j('e.1'), 1000);
//   })
// }).finally(() => {
//   console.log('finally')
// }).then((data) => {
//   console.log('then')
//   console.log(data);
// }).catch((e) => {
//   console.log('catch')
//   console.log(e);
// }).catch((e) => {
//   console.log(e)
// }).then((data) => {
//   console.log(data)
// })

// new Promise((resolve, reject) => {
//   setTimeout(() => {
//     if (Date.now() % 2 === 0) {
//       resolve(1);
//     }
//     else {
//       reject(2);
//     }
//   }, 1000)
// }).then((data) => {
//   console.log(data)
// }, (e) => {
//   console.log(e);
//   console.log('111')
//   return new Promise((r) => {
//     r('success')
//   })
// }).catch((e) => {
//   console.log('222')
//   console.log(e);
// }).then((data) => {
//   console.log(data)
// })

// new Promise((resolve, reject) => {
//   throw 'Promise Error!'
//   // reject(1)
//   resolve(1)
// }).then((data) => {
//   console.log(data)
//   throw 'PPPP'
// }).then((data) => {
//   console.log(data)
// }).catch((e) => {
//   console.log(e)
// })

// Promise.resolve(Promise.resolve(11)).then((data) => {
//   console.log(data)
// }, e => console.log(e))

// async function test() {
//   const a = await new Promise<number>((r) => {
//     console.log(0)
//     setTimeout(() => r(1), 1000)
//   })

//   console.log(a)
//   return a;
// }
// test();

// Promise.all([Promise.resolve(1), Promise.resolve(2), Promise.reject(3)]).then(d => console.log(d)).catch(e => console.log(e))

// Promise.reject(1).finally().finally().then().catch().then((d) => {
//   console.log('then', d);
// }).catch((e) => {
//   console.log(e)
// }).then((d) => {
//   console.log('then', d);
// }).catch((e) => {
//   console.log(e)
// }).finally(() => {
//   console.log('The end')
// })

// Promise.race([new Promise(r => setTimeout(() => r(1), 1000)), new Promise((r, j) => setTimeout(() => j(2), 500)), new Promise(r => setTimeout(() => r(3), 1000))]).then(console.log, console.log)

// Promise.all([new Promise(r => setTimeout(() => r(1), 1000)), new Promise((r, j) => setTimeout(() => r(2), 500)), new Promise(r => setTimeout(() => r(3), 1000))]).then(console.log, console.log)

// Promise.allSettled([new Promise(r => setTimeout(() => r(1), 1000)), new Promise((r, j) => setTimeout(() => j(2), 500)), new Promise(r => setTimeout(() => r(3), 1000))]).then(console.log, console.log)

// const np = new Promise((r, j) => {
//   // setTimeout(r, 0, 1)
//   r(1)
//   console.log(111)
// })
// console.log(0)
// np.then(d => {
//   console.log(d)
// });

// new Promise(() => {
//   setTimeout(() => {
//     throw 1
//   }, 1000)
// }).catch(console.log)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342