Heim > Web-Frontend > js-Tutorial > Hauptteil

Was ist Versprechen? Einführung in Versprechen

不言
Freigeben: 2018-10-17 14:55:13
nach vorne
3559 Leute haben es durchsucht

Der Inhalt dieses Artikels befasst sich mit der Frage: Was ist Promise? Die Einführung von Promise hat einen gewissen Referenzwert. Freunde in Not können sich darauf beziehen.

Eigentlich wollte ich schon lange über die Verwendung von Promise schreiben. Zum einen wird es häufig im eigentlichen Codierungsprozess verwendet, zum anderen stoßen Freunde bei der Verwendung manchmal auf Probleme.

Promise ist in der Tat eine der API-Funktionen in ES6, die wirklich den größten Einfluss auf die Art und Weise hatte, wie Sie JS schreiben.
Dieser Artikel ist eine Zusammenfassung des tatsächlichen Nutzungsprozesses
Wenn man sich die Dateierstellungszeit am 09.10.2017 ansieht, ist der Aufschub wirklich schrecklich. . . Wir müssen unsere Umsetzungsfähigkeiten noch stärken! Vergessen Sie nicht Ihre ursprüngliche Absicht, komm schon!

Vorwort && Grundkonzepte

Promise ist eine Lösung für die JS-Asynchronität. Im Vergleich zu herkömmlichen Rückruffunktionen kann Promise das Problem der schwerwiegenden Verschachtelung mehrerer Rückrufe lösen.

Das Promise-Objekt stellt einen asynchronen Vorgang dar und hat drei Zustände: ausstehend, erfüllt oder abgelehnt. Der Zustandsübergang kann nur ausstehend –> erfüllt oder ausstehend –> sein .

Ich persönlich denke, dass die Erklärung von Promise eigentlich in zwei Teile geteilt werden muss

  1. Für die Gebrauchsanweisung für den Promise-Konstruktor.

  2. Einige Methoden für das Promise-Prototypobjekt.

Promise-Konstruktor

ES6 legt fest, dass das Promise-Objekt ein Konstruktor ist, der zum Generieren von Promise-Instanzen verwendet wird.

Der Promise-Konstruktor akzeptiert eine Funktion als Parameter. Die beiden Parameter der Funktion sind „resolve“ und „reject“. Dabei handelt es sich um zwei Funktionen, die von der JavaScript-Engine bereitgestellt werden und nicht von Ihnen selbst bereitgestellt werden müssen.

Der Zweck der Auflösungsfunktion besteht darin, den Status des Promise-Objekts von „unvollständig“ in „erfolgreich“ zu ändern (d. h. von „ausstehend“ in „erfüllt“). Sie wird aufgerufen, wenn der asynchrone Vorgang erfolgreich ist Das Ergebnis der asynchronen Operation wird als verwendet. Die Funktion der
reject-Funktion besteht darin, den Status des Promise-Objekts von „unvollständig“ in „fehlgeschlagen“ zu ändern (d. h. von „ausstehend“ in „abgelehnt“). , und wird aufgerufen, wenn der asynchrone Vorgang fehlschlägt und der asynchrone Vorgang gemeldet wird. Der Fehler wird als Parameter übergeben.

Der folgende Code erstellt eine Promise-Instanz. Nachdem

function request() {
  return new Promise((resolve, reject) => {
    /* 异步操作成功 */
    setTimeout(() => {
      resolve("success");
    }, 1000);
    // 取消注释这里可以体现,Promise 的状态一旦变更就不会再变化的特性
    // reject('error');
  });
}
Nach dem Login kopieren

request()
  .then(result => {
    console.info(result);
  })
  .catch(error => {
    console.info(error);
  });
Nach dem Login kopieren

das obige new Promise() empfangen hat, können Sie zusätzlich zur Verwendung von Catch zum Abfangen von Fehlern auch die Methode then verwenden, um die Rückruffunktionen und resolve >Es kann auch den Zweck erreichen, Fehler zu erkennen. reject

request().then(
  result => {
    console.info(result);
  },
  error => {
    console.info(error);
  }
);
Nach dem Login kopieren

Methoden für Prototype

Promise.prototype.then()

p.then(onFulfilled, onRejected)
Nach dem Login kopieren

then method ist eine auf Promise.prototype definierte Methode, wie im obigen Beispiel gibt es zwei Parameter, erfüllte Callback-Funktion und abgelehnte Callback-Funktion, der zweite Parameter ist optional.

Zwei wichtige Punkte:

    Der Rückgabewert der then-Methode ist eine neue
  1. -Instanz. Für den Aufrufer wird also immer noch ein

    -Objekt zurückgegeben a Promise nach dem Aufruf von Promise, und sein Verhalten hängt mit dem Rückgabewert der Callback-Funktion in diesem Fall zusammen. Wie folgt: thenPromise

    Wenn die Rückruffunktion dann einen Wert zurückgibt, wird das bis dahin zurückgegebene Versprechen zum akzeptierten Zustand und der zurückgegebene Wert wird berücksichtigt als akzeptierter Zustand.
  • Wenn die Rückruffunktion in dann einen Fehler auslöst, wird das bis dahin zurückgegebene Versprechen zum abgelehnten Status und der ausgegebene Fehler wird als Parameterwert der Rückruffunktion in verwendet der abgelehnte Staat.
  • Wenn die Callback-Funktion in dann ein Promise zurückgibt, das sich bereits im Akzeptanzstatus befindet, wird das bis dahin zurückgegebene Promise auch zum Akzeptanzstatus und die Parameter der Callback-Funktion in Der Akzeptanzstatus dieses Versprechens lautet: Der Wert wird als Parameterwert der Rückruffunktion „Akzeptanzstatus“ des zurückgegebenen Versprechens verwendet.
  • Wenn die Callback-Funktion dann ein Promise zurückgibt, das sich bereits in einem abgelehnten Zustand befindet, wird das bis dahin zurückgegebene Promise ebenfalls in einen abgelehnten Zustand versetzt, und die Parameter der Callback-Funktion von Der abgelehnte Status dieses Versprechens wird sein. Der Wert wird als Parameterwert der Rückruffunktion für den Ablehnungsstatus des zurückgegebenen Versprechens verwendet.
  • Wenn die Callback-Funktion dann ein Promise in einem ausstehenden Status zurückgibt, dann ist der bis dahin zurückgegebene Status des Promise ebenfalls ausstehend, und sein Endstatus ist derselbe wie dieser Promise. ;Gleichzeitig sind die Parameter der Callback-Funktion, die aufgerufen wird, wenn sie den Endzustand erreicht, dieselben wie die Parameter der Callback-Funktion, wenn das Promise den Endzustand erreicht.
    Kettenruf. Konvertieren Sie das Codeformat verschachtelter Rückrufe in einen vertikalen Modus verketteter Aufrufe.
  1. Zum Beispiel ein Rückrufformular: ein Beispiel für die Rückrufhölle
a(a1 => {
  b(a1, b1 => {
    c(b1, c1 => {
      d(c1, d1 => {
        console.log(d1);
      });
    });
  });
});
Nach dem Login kopieren

Eine solche horizontale Erweiterung kann so geändert werden, dass (a, b, c, d) alle Versprechen A zurückgeben vertikale Struktur wie Funktion

a()
  .then(b)
  .then(c)
  .then(d)
  .then(d1 => {
    console.log(d1);
  });
//===== 可能上面的例子并不太好看 ===下面这样更直观
a()
  .then(a1 => b(a1))
  .then(b1 => c(b1))
  .then(c1 => d(c1))
  .then(d1 => {
    console.log(d1);
  });
Nach dem Login kopieren

sieht viel sauberer aus.

Promise.prototype.catch()

Zusätzlich zu then() gibt es auch eine Catch()-Methode in der Promise.prototype-Prototypenkette, die die Handlerfunktion für Ablehnungssituationen ist .

其实 它的行为与调用 Promise.prototype.then(undefined, onRejected) 相同。 (事实上, calling obj.catch(onRejected) 内部 calls obj.then(undefined, onRejected)).

// 1.
request().then(
  result => {
    console.info(result);
  },
  error => {
    console.info(error);
  }
);

// 2.
request()
  .then(result => {
    console.info(result);
  })
  .catch(error => {
    console.info(error);
  });
Nach dem Login kopieren

如上这个例子:两种方式在使用,与结果基本上是等价的,但是 仍然推荐第二种写法,下面我会给出原因:

  1. 在 Promise 链中 Promise.prototype.then(undefined, onRejected),onRejected 方法无法捕获当前 Promise 抛出的错误,而后续的 .catch 可以捕获之前的错误。

  2. 代码冗余

new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("reject");
  }, 1000);
})
  .then(
    result => {
      console.log(result + "1");
      throw Error(result + "1"); // 抛出一个错误
    },
    error => {
      console.log(error + ":1"); // 不会走到这里
    }
  )
  .then(
    result => {
      console.log(result + "2");
      return Promise.resolve(result + "2");
    },
    error => {
      console.log(error + ":2");
    }
  );
// reject1, Error: reject1:2
Nach dem Login kopieren

如果使用 .catch 方法,代码会简化很多,这样实际上是延长了 Promise 链

new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("reject");
  }, 1000);
})
  .then(result => {
    console.log(result + "1");
    throw Error(result + "1"); // 抛出一个错误
  })
  .then(result => {
    console.log(result + "2");
    return Promise.resolve(result + "2");
  })
  .catch(err => {
    console.log(err);
  });
// reject1, Error: reject1:2
Nach dem Login kopieren

Promise.prototype.finally()

暂未完全成为标准的一部分,处于:Stage 4

finally() 方法返回一个 Promise,在执行 then() 和 catch() 后,都会执行finally指定的回调函数。(回调函数中无参数,仅仅代表 Promise 的已经结束

等同于使用 .then + .catch 延长了原有的 Promise 链的效果,避免同样的语句需要在 then() 和 catch() 中各写一次的情况。

mdn-Promise-finally

Promise 对象上的方法

Promise.all() 用来处理 Promise 的并发

Promise.all 会将多个 Promise 实例封装成一个新的 Promise 实例,新的 promise 的状态取决于多个 Promise 实例的状态,只有在全体 Promise 都为 fulfilled 的情况下,新的实例才会变成 fulfilled 状态。;如果参数中 Promise 有一个失败(rejected),此实例回调失败(rejecte),失败原因的是第一个失败 Promise 的结果。

举个例子:

Promise.all([
  new Promise(resolve => {
    setTimeout(resolve, 1000, "p1");
  }),
  new Promise(resolve => {
    setTimeout(resolve, 2000, "p2");
  }),
  new Promise(resolve => {
    setTimeout(resolve, 3000, "p3");
  })
])
  .then(result => {
    console.info("then", result);
  })
  .catch(error => {
    console.info("catch", error);
  });
// [p1,p2,p3]

Promise.all([
  new Promise(resolve => {
    setTimeout(resolve, 1000, "p1");
  }),
  new Promise(resolve => {
    setTimeout(resolve, 2000, "p2");
  }),
  Promise.reject("p3 error")
])
  .then(result => {
    console.info("then", result);
  })
  .catch(error => {
    console.info("catch", error);
  });
// p3 error
Nach dem Login kopieren

获取 cnode 社区的 精华贴的前十条内容

fetch("https://cnodejs.org/api/v1/topics?tab=good&limit=10")
  .then(res => res.json())
  .then(res => {
    const fetchList = res.data.map(item => {
      return fetch(`https://cnodejs.org/api/v1/topic/${item.id}`)
        .then(res => res.json())
        .then(res => res.data);
    });
    Promise.all(fetchList).then(list => {
      console.log(list);
    });
  });
Nach dem Login kopieren

Promise.race() 竞态执行

Promise.race 也会将多个 Promise 实例封装成一个新的Promise实例,只不过新的 Promise 的状态取决于最先改变状态的 Promise 实例的状态。

在前端最典型的一个用法是为 fetch api 模拟请求超时。

Promise.race([
  fetch("https://cnodejs.org/api/v1/topics?tab=good&limit=10").then(res =>
    res.json()
  ),
  new Promise((resolve, reject) => {
    setTimeout(reject, 1, "error");
  })
])
  .then(result => {
    console.info("then", result);
  })
  .catch(error => {
    console.info("catch", error); // 进入这里
  });
Nach dem Login kopieren

上述例子中只要请求 未在 1 毫秒内结束就会进入 .catch() 方法中,虽然不能将请求取消,但是超时模拟却成功了

Promise.resolve(value) && Promise.reject(reason)

这两个方法都能用来创建并返回一个新的 Promise , 区别是 Promise.resolve(value) 携带进新的 Promise 状态是 fulfilled。而 Promise.reject(reason) 带来的 rejected

有的时候可以用来简化一些创建 Promise 的操作如:

const sleep = (time = 0) => new Promise(resolve => setTimeout(resolve, time));
// 这里创建一个 睡眠,并且打印的链
Promise.resolve()
  .then(() => {
    console.log(1);
  })
  .then(() => sleep(1000))
  .then(() => {
    console.log(2);
  })
  .then(() => sleep(2000))
  .then(() => {
    console.log(3);
  });
Nach dem Login kopieren

有时也用来 手动改变 Promise 链中的返回状态 ,当然这样实际上和 直接返回一个值,或者是 使用 throw Error 来构造一个错误,并无区别。到底要怎么用 就看个人喜好了

new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("resolve"); // 1.
  }, 1000);
})
  .then(result => {
    return Promise.reject("reject1"); // 2.
  })
  .then(
    result => {
      return Promise.resolve(result + "2");
    },
    err => {
      return Promise.resolve(err); // 3.
    }
  )
  .then(res => {
    console.log(res); // 4.
  })
  .catch(err => {
    console.log(err + "err");
  });
// reject1
Nach dem Login kopieren

几个例子

下面来看几个例子:

关于执行顺序,具体可搜索,js 循环

new Promise((resolve, reject) => {
  console.log("step 1");
  resolve();
  console.log("step 2");
}).then(() => {
  console.log("step 3");
});
console.log("step 4");

// step 1, step 2, step 4 , step 3
Nach dem Login kopieren

在使用 Promise 构造函数构造 一个 Promise 时,回调函数中的内容就会立即执行,而 Promise.then 中的函数是异步执行的。

关于状态不可变更

let start;
const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    start = Date.now();
    console.log("once");
    resolve("success");
  }, 1000);
});
p.then(res => {
  console.log(res, Date.now() - start);
});
p.then(res => {
  console.log(res, Date.now() - start);
});
p.then(res => {
  console.log(res, Date.now() - start);
});
Nach dem Login kopieren

Promise 构造函数只执行一次,内部状态一旦改变,有了一个值,后续不论调用多少次then()都只拿到那么一个结果。

关于好像状态可以变更

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("success");
  }, 1000);
});

const p2 = p1.then((resolve, reject) => {
  throw new Error("error");
});

console.log("p1", p1);
console.log("p2", p2);

setTimeout(() => {
  console.log("p1", p1);
  console.log("p2", p2);
}, 2000);
Nach dem Login kopieren

观察这一次的打印
第一次打印出两个 Promise 的时候都是 pending ,因为 p2 是基于 p1 的结果,p1 正在 pending ,立即打印出的时候肯定是 pending ;第二次打印的时候,因为 p1 的状态为 resolved ,p2 为 rejected ,这个并不是已经为 fulfilled 状态改变为 rejected ,而是 p2 是一个新的 Promise 实例,then() 返回新的 Promise 实例。

关于透传

Promise.resolve(11)
  .then(1)
  .then(2)
  .then(3)
  .then(res => {
    console.info("res", res);
  });
//   11
Nach dem Login kopieren

给 then 方法传递了一个非函数的值,等同于 then(null),会导致穿透的效果,就是直接过掉了这个 then() ,直到符合规范的 then() 为止。

Promise 的串行调用

使用 Array.reduce 方法串行执行 Promise

const sleep = (time = 0) => new Promise(resolve => setTimeout(resolve, time));
[1000, 2000, 3000, 4000].reduce((Promise, item, index) => {
  return Promise.then(res => {
    console.log(index + 1);
    return sleep(item);
  });
}, Promise.resolve());
// 在分别的等待时间后输出 1,2,3,4
Nach dem Login kopieren

这篇文章到这里就基本上结束了,相信 如果能理解上面的内容,并且在实际项目中使用的话。应该会让工作更高效吧,对于新的异步使用应该也会更加的得心应手。Promise 的使用相对简单,可能后续再出一篇如何实现一个 Promise 吧。

Das obige ist der detaillierte Inhalt vonWas ist Versprechen? Einführung in Versprechen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:segmentfault.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage