这是我从https://scotch.io/tutorials/javascript-promises-for-dummies窃取的代码,并做了一些修改。
var momIsHappy = false;
var getAPhone = function (whatToDoIfPhoneIsPurchased,
whatToDoIfPhoneIsNotPurchased) {
fulfillPromiseToPurchasePhone = whatToDoIfPhoneIsPurchased;
breakPromiseToPurchasePhone = whatToDoIfPhoneIsNotPurchased;
if (momIsHappy) {
var phone = {
brand: 'Samsung',
color: 'black'
};
fulfillPromiseToPurchasePhone(phone); // fulfilled
} else {
var reason = new Error('mom is not happy');
breakPromiseToPurchasePhone(reason); // reject
}
}
var aPhoneIMightGet = new Promise(getAPhone);
var playWithNewPhone = function () {
findOutIfIGetPhone = aPhoneIMightGet;
findOutIfIGetPhone
.then(function (aPhone) {
// yay, you got a new phone
console.log(aPhone);
// output: { brand: 'Samsung', color: 'black' }
})
.catch(function (error) {
// oops, mom don't buy it
console.log(error.message);
// output: 'mom is not happy'
});
};
我不明白的是:getAPhone
何时被调用?我没打电话谁叫的什么时候?怎么样?
答案 0 :(得分:2)
让我们备份一下并描述Promise构造函数的作用。 Promise构造函数传递给一个同步调用的回调。该回调(通常称为“ Promise executor回调”)背后的想法是,它将启动一些异步操作,然后立即返回。稍后,当异步操作完成后,它将解决或拒绝该诺言。
这是一个简单的示例,我们可以逐步进行操作(您可以在下面的代码段中运行此示例以查看日志记录顺序):
console.log("0");
let p = new Promise(function(resolve, reject) {
console.log("1");
setTimeout(function() {
console.log("2");
resolve("done");
}, 1000);
}).then(function(val) {
console.log("3");
});
console.log("4");
您将获得以下输出:
0 // start of the code
1 // Promise executor callback called and setTimeout() initiated
4 // Promise created and now initialized
2 // setTimeout fires
3 // Promise gets resolved and .then() handler called
而且,这是发生的事件的顺序:
console.log("0");
运行new Promise()
并将其传递给回调函数setTimeout()
),但它可能是更复杂的操作,例如执行一些文件操作,搜索数据库等... resolve
。您的示例选择了更长的名称。reject
。由于setTimeout()
是非阻塞且异步的,因此它将启动计时器并立即返回。此时,Promise执行程序回调已完成并返回。setTimeout()
方法。这会为promise注册一个完成回调,然后立即返回。从技术上讲,它返回第二个Promise,该诺言链接到使用Promise构造函数创建的第一个Promise。已注册的此.then()
回调函数已保存,但尚未调用。.then()
记录到控制台。4
的回调。setTimeout()
回调时,它将记录setTimeout()
,然后调用2
。调用resolve("done")
可以解决第一个诺言,并告诉它随后触发任何resolve()
处理程序并调用它们。.then()
的回调并记录.then()
,一切都已完成。现在要回答有关您的代码示例的一些具体问题:
我不明白的是:什么时候叫getAPhone?我没打电话谁叫的什么时候?怎么样?
您将3
传递给Promise构造函数。 Promise构造函数将其作为运行构造函数以创建新Promise对象的一部分进行调用。
这是一个简单的例子:
getAPhone
调用doIt时,会向其传递函数引用(本质上是指向函数的指针)。这样,您要调用的函数就可以在调用函数时使用其想要的任何参数来调用该函数。在这种情况下,function doIt(someCallback) {
someCallback("hi");
}
function myCallback(greeting) {
console.log(greeting);
}
doIt(myCallback); // logs "greeting"
希望您向其传递一个函数引用,它将立即调用该函数并将其传递给doIt()
。
那么,为什么promise构造函数在运行我的函数时不仅仅阻塞我的代码?如果构造函数正在做的就是立即为我调用一个函数,为什么它与直接调用该函数有何不同?
promise构造函数是同步运行的(当您调用"hi"
时)。 Promise构造函数同步运行Promise执行程序回调函数。但是,它通常所做的只是启动异步和非阻塞操作,然后立即返回。然后,异步操作会在后台运行,并在将来完成时触发它自己的回调。
那么,为什么Promise的构造函数中没有代码块?它不是像其他所有函数一样在调用堆栈上起作用吗?
Promise构造函数正在阻塞。它直到完成才返回。像其他所有函数一样,它是调用堆栈上的函数。
在这里可能使您感到困惑的是,您的new Promise()
示例不包含任何异步代码。这是完全同步的。完全没有理由在该代码中使用promises。
以下是该函数的简化版本:
getAPhone()
所有这些操作就是检查var momIsHappy = false;
var getAPhone = function (resolve, reject) {
if (momIsHappy) {
var phone = {
brand: 'Samsung',
color: 'black'
};
resolve(phone); // fulfilled
} else {
var reason = new Error('mom is not happy');
reject(reason); // reject
}
}
,然后立即解决或拒绝诺言。这里没有异步操作。 您完全没有理由在示例中使用promise。 Promise是用于管理和协调异步操作的工具。如果您没有任何异步操作,则不应使用它们,因为当可以使用普通和更简单的函数调用时,它们会增加同步代码的复杂性。使用异步操作,可能难以协调和管理异步操作以及错误处理,尤其是当有多个异步操作需要排序或协调并且处理所有错误时,尤其如此。这就是诺言的目的。
因此,在您的特定情况下,您可以将momIsHappy
设置为常规函数,直接调用它而根本不使用promises。
答案 1 :(得分:0)
用一个简单的例子来测试就不难了:
function someFun() {
console.log("testing")
}
let p = new Promise(someFun)
因此,即使我们对诺言不做任何事情,当您做出诺言并同步运行时,诺言构造函数仍会调用该函数。在更现实的情况下,您可以向其传递一个函数,该函数带有async回调,该回调在异步操作完成时执行,但是传递给new Promise()
的函数仍然会立即触发:
function someFun(resolve) {
console.log("someFun called")
setTimeout(() => resolve("promise resolved"), 1500)
}
console.log("starting")
let p = new Promise(someFun)
.then(console.log)
console.log("just called the promise")
答案 2 :(得分:0)
我不明白的是:什么时候调用“ getAPhone”?我没打电话 它。谁叫的什么时候?怎么样?
也许更直接地回答此问题:当您将新的Promise分配给变量“ aPhoneIMightGet”时,构造函数将按照上面的Mark Meyer的说明运行。
您的“ getAPhone”是传递给Promise构造函数的“执行程序功能”。这样,它会在Promise构造函数返回之前立即执行。这就是所谓的“ getAPhone”功能。
可以找到here的有用文章。